Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

ASP_NET_MVC_4_Framework_s_primerami_na_C_dlya_p

.pdf
Скачиваний:
29
Добавлен:
19.03.2016
Размер:
17.66 Mб
Скачать

<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. Есть три варианта выбора:

,

 

и Replace (по умолчанию).

InsertAfter InsertBefore

 

 

 

 

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 и убеждаемся, что у нас есть цель для нового содержания. Все остальное происходит автоматически, и мы получаем асинхронную форму.

541

Как работает ненавязчивый 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 запросов.

Установка опций Ajax

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

Обеспечение постепенного ухудшения

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

Одна проблема с этим подходом заключается в том, что все это не очень хорошо работает, если пользователь отключил JavaScript (или использует браузер, который не поддерживает его). В таких случаях, когда пользователь отправляет форму, браузер отменяет отображение текущий HTML страницы и заменяет ее фрагментом, возвращенным целевым методом действия. Результат показан на рисунке 21-3.

542

Рисунок 21-3: Результат использования вспомогательного метода Ajax.BeginForm без браузерной поддержки JavaScript

Самым простым способом решения этой проблемы является использование свойства AjaxOptions.Url для определения целевого URL для асинхронного запроса вместо указания имени действия в качестве аргумента метода Ajax.BeginForm, как показано в листинге 21-12.

Листинг 21-12: Использование свойства AjaxOptions.Url для обеспечения постепенного ухудшения

@using HelperMethods.Models @model string

@{

ViewBag.Title = "GetPeople"; AjaxOptions ajaxOpts = new AjaxOptions {

UpdateTargetId = "tableBody",

Url = Url.Action("GetPeopleData")

};

}

<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>

543

@using (Ajax.BeginForm(ajaxOpts)) { <div>

@Html.DropDownList("selectedRole", new SelectList( new [] {"All"}.Concat(Enum.GetNames(typeof(Role)))))

<button type="submit">Submit</button> </div>

}

Мы использовали вспомогательный метод Url.Action для создания URL, который будет вызывать действие GetPeopleData, и использовали версию метода Ajax.BeginForm, который принимает только параметр AjaxOptions. В результате этого создается элемент form, который отправляется обратно в исходный метод действия, если JavaScript не включен:

...

<form action="/People/GetPeople" data-ajax="true" data-ajax-mode="replace"

data-ajax-update="#tableBody" data-ajax-url="/People/GetPeopleData" id="form0"

method="post">

...

Если JavaScript включен, то библиотека ненавязчивого Ajax примет целевой URL из атрибута data- ajax-url, который относится к дочернему действию. Если JavaScript отключен, то браузер будет использовать обычную методику размещения формы, когда целевой URL принимается от атрибута action, указывающего обратно на метод действия, который будет генерировать полную HTML страницу.

Внимание

Вы можете удивиться, почему мы так заботимся о пользователях, которые отключили JavaScript. И кто же эти пользователи? На самом деле, такие пользователи делятся на две группы. Первая группа состоит из тех, кто очень серьезно воспринимает свою IT-безопасность и отключает все, что может быть использовано для атак: а этим JavaScript славится уже на протяжении многих лет. Вторая группа – это пользователи в крупных корпорациях, где применяется невероятная ограничительная политика во имя IT-безопасности (хотя, по нашему опыту, корпоративные ПК так плохо настроены, что безопасности тут просто не существует, а ограничения лишь раздражают пользователей). Вы можете игнорировать постепенное ухудшение, если чувствуете, что можете игнорировать экспертов по безопасности и людей, которые работают для крупных компаний. Но так как они могут быть технически подкованными и знающими пользователями, мы всегда уделяем время на то, чтобы не оставлять их в стороне.

Предоставление пользователям обратной связи при создании Ajax запроса

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

AjaxOptions.LoadingElementId и AjaxOptions.LoadingElementDuration. В листинге 21-13

показано, как мы применили эти свойства для файла представления GetPerson.cshtml.

Листинг 21-13: Создание обратной связи с пользователем при помощи свойства LoadingElementId

@using HelperMethods.Models @model string

@{

544

ViewBag.Title = "GetPeople"; AjaxOptions ajaxOpts = new AjaxOptions {

UpdateTargetId = "tableBody",

Url = Url.Action("GetPeopleData"),

LoadingElementId = "loading",

LoadingElementDuration = 1000,

};

}

<h2>Get People</h2>

<div id="loading" class="load" style="display: none"> <p>Loading Data...</p>

</div>

<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(ajaxOpts)) { <div>

@Html.DropDownList("selectedRole", new SelectList( new [] {"All"}.Concat(Enum.GetNames(typeof(Role)))))

<button type="submit">Submit</button> </div>

}

Свойство AjaxOptions.LoadingElementId определяет значение атрибута id скрытого HTML элемента, который будет показан пользователю, когда выполняется Ajax запрос. Чтобы показать эту возможность, мы добавили к представлению элемент div, который мы скрыли от пользователя, установив значение CSS свойства display на none. Мы дали этому элементу div id атрибут loading и использовали этот id в качестве значения для свойства LoadingElementId. Ненавязчивый Ajax будет отображать элемент для пользователя во время выполнения запроса, как показано на рисунке 21-4. Свойство LoadingElementDuration задает продолжительность анимации, который используется, чтобы показать элемент loading пользователю. Мы определили значение 1000, которое обозначает одну секунду.

Рисунок 21-4: Обратная связь с пользователем во время выполнения Ajax запроса

545

Подсказка для пользователя перед тем, как он сделал запрос

Свойство AjaxOptions.Confirm позволяет нам указать сообщение, которое будет использоваться как подсказка для пользователя перед каждым асинхронным запросом. Пользователь может выбрать дальнейшее выполнение или отмену запроса. В листинге 21-14 показано, как мы применили это свойство в файле GetPerson.cshtml.

Листинг 21-14: Подсказка для пользователя перед тем, как он сделал запрос

...

@{

ViewBag.Title = "GetPeople"; AjaxOptions ajaxOpts = new AjaxOptions {

UpdateTargetId = "tableBody",

Url = Url.Action("GetPeopleData"), LoadingElementId = "loading", LoadingElementDuration = 1000,

Confirm = "Do you wish to request new data?"

};

}

...

С этим дополнением пользователю каждый раз при отправки формы показывается окно с сообщением, как представлено на рисунке 21-5. Это окно предлагается пользователю при каждом запросе. Это означает, что данную функцию следует использовать с осторожностью, чтобы не раздражать пользователя.

Рисунок 21-5: Окно с сообщением для пользователя перед отправкой запроса

Создание Ajax ссылок

В дополнение к формам мы можем использовать ненавязчивый Ajax для создания асинхронных элементов a. Механизм этого очень похоже на то, как работают Ajax формы. Вы можете увидеть, как мы добавили ссылки в представление Ajax GetPeople.cshtml, в листинге 21-15.

Листинг 21-15: Создание ссылок при помощи Ajax

@using HelperMethods.Models @model string

@{

ViewBag.Title = "GetPeople"; AjaxOptions ajaxOpts = new AjaxOptions {

UpdateTargetId = "tableBody",

Url = Url.Action("GetPeopleData"),

546

LoadingElementId = "loading",

LoadingElementDuration = 1000,

Confirm = "Do you wish to request new data?" };

}

<h2>Get People</h2>

<div id="loading" class="load" style="display: none"> <p>Loading Data...</p>

</div>

<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(ajaxOpts)) { <div>

@Html.DropDownList("selectedRole", new SelectList( new [] {"All"}.Concat(Enum.GetNames(typeof(Role)))))

<button type="submit">Submit</button> </div>

}

<div>

@foreach (string role in Enum.GetNames(typeof(Role))) { <div class="ajaxLink">

@Ajax.ActionLink(role, "GetPeopleData", new {selectedRole = role},

new AjaxOptions {UpdateTargetId = "tableBody"}) </div>

}

</div>

Мы использовали цикл foreach, чтобы вызвать вспомогательный метод Ajax.ActionLink для каждого из значений, определенных перечислением Role, создав набор элементов a с поддержкой Ajax. Созданные элементы a имеют такие же атрибуты data, которые мы видели при работе с формами:

...

<a data-ajax="true" data-ajax-mode="replace" data-ajax-update="#tableBody"

href="/People/GetPeopleData?selectedRole=Guest">Guest</a>

...

Наша конфигурация маршрутизации не имеет записи для переменной selectedRole, поэтому URL, который был создан для атрибута href, определяет ту роль, которую представляет ссылка, используя строковый компонент запроса URL.

Вы можете увидеть ссылки, которые мы добавили в представление, на рисунке 21-6. Нажатие по одной из этих ссылок вызовет метод действия GetPersonData действия и заменит содержимое элемент tbody возвращенным HTML фрагментом. Это создает тот же результат фильтрации данных, которого мы достигли с помощью Ajax формы ранее в этой главе.

547

Рисунок 21-6: Использование Ajax ссылок в представлении

Совет

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

Обеспечение постепенного ухудшения для ссылок

Мы столкнулись с той же проблемой с Ajax ссылками, которая у нас возникла с Ajax формами: когда нет браузерной поддержки JavaScript, нажатие по одной из ссылок будет просто отображать HTML фрагмент, который генерирует метод действия GetPeopleData.

Мы решаем эту проблему с помощью свойства AjaxOptions.Url, чтобы указать URL для Ajax запроса, и мы задаем действие GetPeople для вспомогательного метода Ajax.ActionLink, как показано в листинге 21-16.

Листинг 21-16: Создание постепенного ухудшения для Ajax ссылок

<div>

@foreach (string role in Enum.GetNames(typeof(Role))) { <div class="ajaxLink">

@Ajax.ActionLink(role, "GetPeople", new {selectedRole = role},

548

new AjaxOptions { UpdateTargetId = "tableBody",

Url = Url.Action("GetPeopleData", new {selectedRole = role})

})

</div>

}

</div>

...

Именно поэтому мы создаем новый объект AjaxOptions для каждой из требуемых ссылок, а не использовали ту, которую мы создали в блоке кода Razor для элемента form. Независимый AjaxOptions позволяет нам указать различные значения для свойства Url для каждой ссылки и поддерживает постепенное ухудшение для браузеров без JavaScript.

Работа с функциями обратного вызова Ajax

Класс AjaxOptions определяет набор свойств, которые позволяют нам указать JavaScript функции, которые будут вызываться в различных точках жизненного цикла Ajax запроса. Эти свойства описаны в таблице 21-3.

Таблица 21-3: Свойства обратного вызова AjaxOptions

Свойство

Событие

Описание

jQuery

 

 

 

 

 

OnBegin

beforeSend

Вызывается непосредственно перед отправлением запроса

 

 

 

OnComplete

complete

Вызывается, если запрос был выполнен, независимо от того, успешно

или нет

 

 

 

 

 

OnFailure

error

Вызывается, если запрос выполнен неудачно

 

 

 

OnSuccess

success

Вызывается, если запрос выполнен успешно

Каждое из свойств обратного вызова AjaxOptions соотносится с событием Ajax, поддерживаемым библиотекой JQuery. Мы перечислили JQuery события в таблице 21-3 для тех читателей, которые раньше использовали JQuery. Вы можете получить подробную информацию о каждом из этих событий и параметрах, которые будут переданы вашей функции, на http://api.jquery.com/jQuery.ajax.

В листинге 21-17 можно увидеть, как мы использовали элемент script для определения некоторых базовых функций JavaScript, которые будут отчитываться о ходе Ajax запроса, и использовали свойства, показанные в таблице 21-3, чтобы указать наши функции в качестве обработчиков Ajax событий.

Листинг 21-17: Использование функций обратного вызова Ajax

@using HelperMethods.Models @model string

@{

ViewBag.Title = "GetPeople"; AjaxOptions ajaxOpts = new AjaxOptions {

UpdateTargetId = "tableBody",

Url = Url.Action("GetPeopleData"), LoadingElementId = "loading", LoadingElementDuration = 1000,

Confirm = "Do you wish to request new data?" };

}

<script type="text/javascript"> function OnBegin() {

549

alert("This is the OnBegin Callback");

}

function OnSuccess(data) {

alert("This is the OnSuccessCallback: " + data);

}

function OnFailure(request, error) {

alert("This is the OnFailure Callback:" + error);

}

function OnComplete(request, status) {

alert("This is the OnComplete Callback: " + status);

}

</script>

<h2>Get People</h2>

<div id="loading" class="load" style="display: none"> <p>Loading Data...</p>

</div>

<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(ajaxOpts)) { <div>

@Html.DropDownList("selectedRole", new SelectList( new [] {"All"}.Concat(Enum.GetNames(typeof(Role)))))

<button type="submit">Submit</button> </div>

}

<div>

@foreach (string role in Enum.GetNames(typeof(Role))) { <div class="ajaxLink">

@Ajax.ActionLink(role, "GetPeople", new {selectedRole = role},

new AjaxOptions { UpdateTargetId = "tableBody",

Url = Url.Action("GetPeopleData", new {selectedRole = role}),

OnBegin = "OnBegin", OnFailure = "OnFailure", OnSuccess = "OnSuccess", OnComplete = "OnComplete"

})

</div>

}

</div>

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

550

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]