Главная страница   /   25.5. Написание JavaScript кода для использования Web API (ASP.NET MVC 4

ASP.NET MVC 4

ASP.NET MVC 4

Адам Фриман

25.5. Написание JavaScript кода для использования Web API

Мы создали наш контроллер API и объяснили, как URL вида /api/reservation/3 сопоставляется с методом действия в зависимости от метода HTTP. Теперь пора написать код JavaScript, с помощью которого мы будем использовать созданный Web API. Мы будем использовать jQuery, чтобы управлять HTML-элементами представления Views/Home/Index.cshtml и обрабатывать запросы Ajax, которые будем отправлять к действиям контроллера Reservation.

jQuery - это отличная многофункциональная библиотека JavaScript, которую мы часто используем в собственных проектах и рекомендуем к использованию вам. В этой книге мы не сможем поместить руководство по jQuery, поэтому будем создавать функциональность JavaScript и рассказывать вам, что делает каждый блок кода, не вдаваясь в подробности о том, как работают функции jQuery. Дополнительные сведения о jQuery можно найти на сайте jquery.com или в книге Адама Pro jQuery.

Создаем базовую функциональность

Для начала мы создадим папку /Scripts/Home и добавим в нее новый файл JavaScript под названием Index.js (как упоминалось в главе 24, мы организовываем скрипты для отдельных приложений, следуя соглашению). Прежде чем сделать что-нибудь еще, мы добавим элемент script к определению секции scripts в представлении /Views/Home/Index.cshtml, который будет загружать наш код JavaScript, как показано в листинге 25-11.

Листинг 25-11: Добавляем элемент script для файла Index.js в представление Index.cshtml
@{
	ViewBag.Title = "Index";
}

@section scripts {
	<script src="~/Scripts/jquery.unobtrusive-ajax.js"></script>
	<script src="~/Scripts/Home/Index.js"></script>
}

Далее мы добавим в файл Index.js необходимые базовые функции, как показано в листинге 25-12.

Листинг 25-12: Добавляем базовые функции в файл Index.js
function selectView(view) {
	$('.display').not('#' + view + "Display").hide();
	$('#' + view + "Display").show();
}
function getData() {
	$.ajax({
		type: "GET",
		url: "/api/reservation",
		success: function (data) {
			$('#tableBody').empty();
			for (var i = 0; i < data.length; i++) {
				$('#tableBody').append('<tr><td><input id="id" name="id" type="radio"'
				+ 'value="' + data[i].ReservationId + '" /></td>'
				+ '<td>' + data[i].ClientName + '</td>'
				+ '<td>' + data[i].Location + '</td></tr>');
			}
			$('input:radio')[0].checked = "checked";
			selectView("summary");
		}
	});
}
$(document).ready(function () {
	selectView("summary");
	getData();
	$("button").click(function (e) {
		var selectedRadio = $('input:radio:checked')
		switch (e.target.id) {
			case "refresh":
				getData();
				break;
			case "delete":
				break;
			case "add":
				selectView("add");
				break;
			case "edit":
				selectView("edit");
				break;
			case "submitEdit":
				break;
		}
	});
});

Мы определили три функции. Первая, selectView, изменяет видимость элементов div в классе display, так что отображаться будет только один набор элементов. Вторая функция, GetData, использует поддержку Ajax в jQuery для отправки запросов по адресу /api/reservation. Для добавления строк в таблицу в представлении используется массив объектов JSON; он заменяет заполнитель The data is loading, который был виден на рисунке 25-1 . Каждая строка в таблице содержит переключатель, с помощью которого пользователь сможет отредактировать или удалить объект Reservation.

Последняя функция будет передана в функцию jQuery ready, что означает, что она не будет выполнена до окончания загрузки и обработки содержимого страницы браузером. Мы вызываем функцию selectView для отображения только содержимого элемента summaryDisplay, getData - для загрузки данных по ссылке /api/reservation (как мы продемонстрировали ранее, это приведет к вызову метода GetAllReservations в контроллере Reservation). Мы также настроили обработчик событий, который будет выполняться после нажатия любой кнопки на странице. Мы использовали оператор switch, чтобы различать элементы button в зависимости от значения атрибута id. В его операторе case мы создаем различные запросы, которые затем отправим на сервер.

В данный момент для кнопки Refresh мы вызываем функцию getData, которая перезагружает данные от сервера, для кнопок Edit и Add - функцию selectView, которая отображает элементы, необходимые для создания и редактирования объектов модели.

Если вы запустите приложение и перейдете по корневой ссылке, то увидите изменения, созданные нашим базовым кодом JavaScript, как показано на рисунке 25-3.

Рисунок 25-3: Результат выполнения JavaScript кода

Добавляем поддержку редактирования новых объектов Reservation

Мы хотим использовать все методы действий контроллера Reservation, поэтому наш подход к редактированию объектов Reservation будет немного странным. В документе HTML у нас уже есть все необходимые данные для редактирования объекта Reservation, но мы запросим у сервера один объект Reservation, чтобы использовать объект GetReservation. В листинге 25-13 показано, как мы добавили операторы в файл Index.js для ответа на нажатие кнопки Edit.

Листинг 25-13: Отвечаем на нажатие кнопки Edit
$(document).ready(function() {
	selectView("summary");
	getData();
	$("button").click(function(e) {
		var selectedRadio = $('input:radio:checked')
		switch (e.target.id) {
		case "refresh":
			getData();
			break;
		case "delete":
			break;
		case "add":
			selectView("add");
			break;
		case "edit":
			$.ajax({
				type: "GET",
				url: "/api/reservation/" + selectedRadio.attr('value'),
				success: function(data) {
					$('#editReservationId').val(data.ReservationId);
					$('#editClientName').val(data.ClientName);
					$('#editLocation').val(data.Location);
					selectView("edit");
				}
			});
			break;
		case "submitEdit":
			break;
		}
	});
});

При создании строк таблицы в функции getData мы использовали значение свойства ReservationId каждого объекта Reservation, чтобы установить значение для элемента radio button, например:

<input name="id" id="id" type="radio" value="3"/>

Когда пользователь нажимает кнопку Edit, мы находим выбранный переключатель и используем его атрибут value в URL, который запросим у сервера. Если пользователь выбрал радиокнопку, показанную ранее, то мы запросим URL /api/reservation/3. Мы сообщаем jQuery, что хотим отправить запрос GET, и сочетание URL и метода HTTP приводят нас к методу действия GetReservation контроллера Reservation.

Мы используем полученные данные JSON, чтобы установить значения элементов input в секции editDisplay, а затем вызываем функцию selectView, чтобы отобразить их пользователю, как показано на рисунке 25-4.

Рисунок 25-4: Выбор объекта для редактирования

Чтобы разрешить пользователю сохранить изменения, нам нужно заполнить блок case, который работает с id кнопки submitEdit, как показано в листинге 25-14.

Листинг 25-14: Сохраняем изменения на сервере
$(document).ready(function () {
	selectView("summary");
	getData();
	$("button").click(function (e) {
		var selectedRadio = $('input:radio:checked')
		switch (e.target.id) {
			case "refresh":
				getData();
				break;
			case "delete":
				break;
			case "add":
				selectView("add");
				break;
			case "edit":
				$.ajax({
					type: "GET",
					url: "/api/reservation/" + selectedRadio.attr('value'),
					success: function (data) {
						$('#editReservationId').val(data.ReservationId);
						$('#editClientName').val(data.ClientName);
						$('#editLocation').val(data.Location);
						selectView("edit");
					}
				});
				break;
			case "submitEdit":
				$.ajax({
					type: "PUT",
					url: "/api/reservation/" + selectedRadio.attr('value'),
					data: $('#editForm').serialize(),
					success: function (result) {
						if (result) {
							var cells = selectedRadio.closest('tr').children();
							cells[1].innerText = $('#editClientName').val();
							cells[2].innerText = $('#editLocation').val();
							selectView("summary");
						}
					}
				});
				break;
		}
	});
});

Мы используем те же URL, что и для получения объекта Reservation, /api/reservation/3, но с методом HTTP PUT, следовательно, для обработки запроса будет использоваться метод действия PutReservation контроллера Reservation. Напомним, мы определили его следующим образом:

public bool PutReservation(Reservation item) {
	return repo.Update(item);
}

Обратите внимание, что аргументом этого метода действия является объект Reservation. Контроллеры API используют те же механизмы связывания, которые мы описали в главе 22, что означает, что нам не придется преобразовывать данные запроса в объект модели.

Добавляем поддержку удаления объектов Reservation

Вы уже поняли принцип работы API, и как метод HTTP изменяет метод действия, который будет обрабатывать наш запрос, даже если мы отправляем его по той же ссылке. В листинге 25-15 показано, как мы добавили поддержку удаления объектов Reservation, для чего используется метод HTTP DELETE.

Листинг 25-15: Добавляем поддержку удаления объектов Reservation
case "delete":
	$.ajax({
		type: "DELETE",
		url: "/api/reservation/" + selectedRadio.attr('value'),
		success: function (data) {
			selectedRadio.closest('tr').remove();
		}
	});
	break;

В элементе table мы удаляем строку, которая содержит данные объекта Reservation, который был удален. Мы делаем это независимо от результата, который получим от сервера, что не будет иметь смысла в реальном проекте.

Добавляем поддержку создания объектов Reservation

Для создания новых объектов Reservation мы применим несколько иной подход. Для создания запросов PUT или DELETE легче будет использовать поддержку Ajax в jQuery, но для запросов POST и GET можно без проблем использовать ненавязчивый Ajax. Чтобы добавить поддержку создания новых объектов данных, нам понадобится только настроить объект AjaxOptions, который мы используем во вспомогательном методе Ajax.BeginForm в представлении Index.cshtml, как показано в листинге 25-16.

Подсказка

Если вы хотите использовать формы Ajax для всех запросов, или вы хотите использовать REST-сервис в браузере, который поддерживает только методы GET и POST, то с помощью вспомогательного метода Html.HttpMethodOverride вы можете добавить в форму скрытый элемент, который будет интерпретирован контроллером API и использован для обращения к методам действий. Переопределять можно только запросы POST, но эта резервная техника может быть полезной, особенно для старых браузеров.

Листинг 25-16: Настраиваем объект AjaxOptions для создания новых объектов модели
<div id="addDisplay" class="display">
	<h4>Add New Reservation</h4>
	@{
		AjaxOptions addAjaxOpts = new AjaxOptions
		{
			OnSuccess = "getData",
			Url = "/api/reservation"
		};
	}
	@using (Ajax.BeginForm(addAjaxOpts))
	{
		@Html.Hidden("ReservationId", 0)
		<p><label>Name:</label>@Html.Editor("ClientName")</p>
		<p><label>Location:</label>@Html.Editor("Location")</p>
		<button type="submit">Submit</button>
	}
</div>

Эта форма будет отправлена по умолчанию с помощью метода POST, и нам не нужно создавать URL динамически, потому что метод действия PostReservation не принимает переменные сегментов в качестве параметров (он принимает объект Reservation, который создается механизмом связывания). Когда пользователь отправляет форму на сервер, будет вызван метод действия PostReservation, который создаст в хранилище новый объект Reservation. Когда запрос завершен, мы вызываем метод getData, чтобы обновить данные клиента и отобразить итоговое представление. Для простоты кода JavaScript мы этого не делаем, хотя сервер и отправляет нам вновь созданный объект в формате JSON, с помощью которого мы могли бы добавить в таблицу новую строку. Результат создания нового объекта Reservation показан на рисунке 25-5.

Рисунок 25-5: Добавляем новый объект Reservation

И это весь код, необходимый для завершения нашего Web API и простого приложения, в котором он используется. Как мы заметили ранее в этой главе, функция Web API очень проста, и все время уйдет на создание и тестирование клиента, который его использует. Чтобы создать сам API, необходимо наследовать новый контроллер от ApiController и создать методы действий с теми же именами, что и методы HTTP, с помощью которых вы хотите к ним обращаться.