Главная страница   /   21.4. Создание "ненавязчивой" Ajax формы (ASP.NET MVC 4

ASP.NET MVC 4

ASP.NET MVC 4

Адам Фриман

21.4. Создание "ненавязчивой" Ajax формы

Теперь мы готовы начать применять ненавязчивого Ajax в нашем приложении, начиная с формы с ненавязчивым Ajax. В последующих разделах мы рассмотрим процесс замены обычных синхронных форм эквивалентным Ajax и объясним, как работает ненавязчивый Ajax.

Подготовка контроллера

Наша цель состоит в том, чтобы менялись только данные HTML элемента table, когда пользователь нажимает на кнопку Submit в нашем приложении. Это означает, что первое, что нам нужно сделать, это переделать методы действия в нашем контроллере People так, чтобы мы могли получить только те данные, которые нам нужны. Вы можете увидеть изменения, которые мы внесли в контроллер People, в листинге 21-8.

Листинг 21-8: Изменение методов действий в контроллере People
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using HelperMethods.Models;
namespace HelperMethods.Controllers
{
	public class PeopleController : Controller
	{
		private Person[] personData = {
			new Person {FirstName = "Adam", LastName = "Freeman", Role = Role.Admin},
			new Person {FirstName = "Steven", LastName = "Sanderson", Role = Role.Admin},
			new Person {FirstName = "Jacqui", LastName = "Griffyth", Role = Role.User},
			new Person {FirstName = "John", LastName = "Smith", Role = Role.User},
			new Person {FirstName = "Anne", LastName = "Jones", Role = Role.Guest}
		};
		public ActionResult Index()
		{
			return View();
		}
		public PartialViewResult GetPeopleData(string selectedRole = "All")
		{
			IEnumerable<Person> data = personData;
			if (selectedRole != "All")
			{
				Role selected = (Role)Enum.Parse(typeof(Role), selectedRole);
				data = personData.Where(p => p.Role == selected);
			}
			return PartialView(data);
		}
		public ActionResult GetPeople(string selectedRole = "All")
		{
			return View((object)selectedRole);
		}
	}
}

Мы добавили действие GetPeopleData, оно выбирает объекты Person, которые нам нужно отобразить, и передает их методу PartialView для создания требуемых строк таблицы. Поскольку выборка данных обрабатывается методом действия GetPeopleData, мы можем сильно упростить метод действия GetPeople и полностью удалить версию HttpPost. Цель этого метода состоит в передаче выбранной роли в виде string в представление.

Мы создали новый файл частичного представления /Views/People/GetPeopleData.cshtml для нового метода действия GetPeopleData. Вы можете увидеть содержимое представления в листинге 21-9. Это представление отвечает за генерацию элементов tr, которые будут заполнять таблицу, используя перечисление объектов Person, которые передаются от метода действия.

Листинг 21-9: Создание представления GetPeopleData.cshtml
@using HelperMethods.Models
@model IEnumerable<Person>
@foreach (Person p in Model) {
	<tr>
		<td>@p.FirstName</td>
		<td>@p.LastName</td>
		<td>@p.Role</td>
	</tr>
}

Мы также должны обновить представление /Views/People/GetPeople.cshtml, которое вы можете увидеть в листинге 21-10.

Листинг 21-10: Обновление представления GetPeople.cshtml
@using HelperMethods.Models
@model string
@{
ViewBag.Title = "GetPeople";
}
<h2>Get People</h2>
<table>
	<thead>
		<tr>
			<th>First</th>
			<th>Last</th>
			<th>Role</th>
		</tr>
	</thead>
	<tbody>
		@Html.Action("GetPeopleData", new {selectedRole = Model })
	</tbody>
</table>
@using (Html.BeginForm()) {
<div>
	@Html.DropDownList("selectedRole", new SelectList(
		new [] {"All"}.Concat(Enum.GetNames(typeof(Role)))))
	<button type="submit">Submit</button>
</div>
}

Мы изменили тип модели представления на string, который мы передаем вспомогательному методу Html.Action для вызова дочернего действия GetPeopleData. Это рендерит частичное представление и дает нам строки таблицы.

Создание Ajax формы

У нас после этих изменений еще есть синхронная форма в приложении, но мы выделили функциональность контроллера таким образом, мы можем запрашивать только строки таблицы через действие GetPeopleData. Этот новый метод действия будет целью нашего Ajax запроса, и следующим шагом является обновление представления GetPeople.cshtml, таким образом, чтобы работа с формой осуществлялась через Ajax, как показано в листинге 21-11.

Листинг 21-11: Создание ненавязчивой Ajax формы в представлении GetPeople.cshtml
@using HelperMethods.Models
@model string
@{
	ViewBag.Title = "GetPeople";
	AjaxOptions ajaxOpts = new AjaxOptions {
		UpdateTargetId = "tableBody"
	};
}
<h2>Get People</h2>
<table>
	<thead>
		<tr>
			<th>First</th>
			<th>Last</th>
			<th>Role</th>
		</tr>
	</thead>
	<tbody id="tableBody">
		@Html.Action("GetPeopleData", new {selectedRole = Model })
	</tbody>
</table>
@using (Ajax.BeginForm("GetPeopleData", ajaxOpts)) {
<div>
	@Html.DropDownList("selectedRole", new SelectList(
		new [] {"All"}.Concat(Enum.GetNames(typeof(Role)))))
	<button type="submit">Submit</button>
</div>
}

Как вы можете видеть, изменения относительно мелкие, и нам не нужно вставлять блоки кода вокруг представления, чтобы все работало.

В центре поддержки MVC фреймворком Ajax форм находится вспомогательный метод Ajax.BeginForm, который принимает в качестве аргумента объект AjaxOptions. Нам нравится создавать объекты AjaxOptions при запуске представления в блоке кода Razor, но вы можете создать их внутри, когда вызываете Ajax.BeginForm.

Класс AjaxOptions, находящийся в пространстве имен System.Web.Mvc.Ajax, определяет свойства, которые позволяют нам конфигурировать то, как делается асинхронный запрос к серверу и что происходит с данными, которые мы получаем обратно. Эти свойства описаны в таблице 21 2.

Таблица 21-2: Свойства AjaxOptions
Свойство Описание
Confirm Задает сообщение, которое будет отображаться для пользователя в окне подтверждения, прежде чем будет сделан Ajax запрос.
HttpMethod Задает HTTP метод, который будет использоваться для создания запроса. Это может быть либо Get, либо Post.
InsertionMode Указывает способ, которым содержание, полученное с сервера, будет вставлено в HTML. Есть три варианта выбора: InsertAfter, InsertBefore и Replace (по умолчанию).
LoadingElementId Указывает ID HTML элемента, который будет отображаться, пока выполняется Ajax запрос.
LoadingElementDuration Задает продолжительность анимации, которая используется для выявления элемента, определенного LoadingElementId.
UpdateTargetId Указывает ID HTML элемента, в который будет вставлен контент, полученный от сервера.
Url Задает Url, который будет запрашиваться сервером.

В листинге мы установили свойство UpdateTargetId для tableBody. Это id, которое мы присвоили HTML элементу tbody в представлении в листинге 21-11. Когда пользователь нажмет на кнопку Submit, асинхронный запрос будет сделан к методу действия GetPeopleData, а возвращенный HTML фрагмент будет использоваться для замены существующих элементов в tbody.

Совет

Класс AjaxOptions также определяет свойства, которые позволяют нам указать функции обратного вызова для различных этапов жизненного цикла запроса, см. «Работа с функциями обратного вызова Ajax" далее в этой главе.

Ну вот и все: мы заменяем метод Html.BeginForm Ajax.BeginForm и убеждаемся, что у нас есть цель для нового содержания. Все остальное происходит автоматически, и мы получаем асинхронную форму.

Как работает ненавязчивый Ajax

Когда мы вызываем вспомогательный метод Ajax.BeginForm, параметры, которые мы указали при помощи объекта AjaxOptions, превращаются в атрибуты, применяемые к элементу form. Наше представление в листинге 21-11 создает следующий элемент form:

...
<form action="/People/GetPeopleData" data-ajax="true" data-ajax-mode="replace"
	data-ajax-update="#tableBody" id="form0" method="post">
...

Когда HTML страница, полученная из представления GetPeople.cshtml, загружается в браузер, JavaScript в библиотеке jquery.unobtrusive-ajax.js сканирует HTML элементы и определяет Ajax форму, когда ищет элементы, у которых атрибуты data-ajax имеют значение true.

Остальные атрибуты, имена которых начинаются с data-ajax, содержат значения, которые мы задали с помощью класса AjaxOptions. Эти параметры конфигурации используются для настройки JQuery, который имеет встроенную поддержку для управления Ajax запросами.

Совет

Вы не обязательно должны использовать MVC фреймворк для поддержки ненавязчиво Ajax. Есть много альтернатив, в том числе использование JQuery напрямую. То есть, вы можете выбрать определенную технику и придерживаться ее. Мы не рекомендуем смешивать MVC поддержку ненавязчивого Ajax с другими методами и библиотеками в одном и том же представлении, поскольку это может вызвать некоторые проблемы, такие как дублирование или падение Ajax запросов.