ASP.NET MVC 4
Адам Фриман
Написание 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, с помощью которых вы хотите к ним обращаться.