Asynchronous Javascript And XML ASP.NET MVC 4.0 2013 1 Содержание • Базовый уровень AJAX • AJAX в jQuery • AJAX хелперы 2 Базовый уровень 1. var ajax = new XMLHttpRequest(); 2. ajax.open() 3. ajax.send() Web страница XMLHttpRequest Web сервер Контроллер Метод Обработчик события onreadystatechange 3 Пример: Продолжение строки На странице – поле ввода. При вводе очередной буквы внизу высвечивается возможное продолжение строки. 4 Пример: на сервере Метод контроллера Home.Details public ContentResult Details(string word) { if (string.IsNullOrEmpty(word)) return null; var details = lukom.Split(new char[] {'\n', '\r'}, StringSplitOptions.RemoveEmptyEntries) .Where(s => s.ToLower().StartsWith(word)) .Aggregate("", (a, s) => a = a + "\n" + s ); return Content(details); } const string lukom = @" У лукоморья дуб зелёный; Златая цепь на дубе том: И днем и ночью кот учёный ... 5 Пример: javascript на клиенте $(function () { $("[name = 'word']").keyup(function () { request(this.value); }) }); // Запрос AJAX function request(word) { var ajax = new XMLHttpRequest(); var url = "/Home/Details?word=" + word; ajax.open("GET", url, true); ajax.onreadystatechange = function () { response(ajax); }; ajax.send(null); // Отправляем запрос $("#details").text("Загрузка..."); } // Обработчик изменения состояния объекта AJAX function response(ajax) { // Обрабатываем асинхронный запрос if (ajax.readyState == 4) { if (ajax.status == 200) { // Запрос успешно обработан var answer = ajax.responseText; $("#details").html(answer); } else { $("#details").text("Ошибка..."); } } } 6 Как добавить ссылку на js ~/App_Start/BundleConfig.cs public static void RegisterBundles(BundleCollection bundles) { bundles.Add(new ScriptBundle("~/bundles/jquery").Include( "~/Scripts/jquery-{version}.js").Include( "~/Scripts/index.js") ); ~/Views/Shared/_Layout.cshtml <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=devicewidth" /> <title>@ViewBag.Title</title> @Styles.Render("~/Content/css") @Scripts.Render("~/bundles/modernizr") </head> <body> @RenderBody() @Scripts.Render("~/bundles/jquery") @RenderSection("scripts", required: false) </body> </html> 7 AJAX в jQuery 8 Тот же пример // Запрос AJAX function request(word) { var ajax = new XMLHttpRequest(); var url = "/Home/Details?word=" + word; ajax.open("GET", url, true); ajax.onreadystatechange = function () { response(ajax); }; function { ajax.send(null); //request(word) Отправляем запрос var url = "/Home/Details?word=" + word; $("#details").text("Загрузка..."); $.get(url, function (answer) { } $("#details").html(answer); // Обработчик изменения состояния объекта AJAX }); function response(ajax) { } // Обрабатываем асинхронный запрос if (ajax.readyState == 4) { if (ajax.status == 200) { // Запрос успешно обработан var answer = ajax.responseText; $("#details").html(answer); } else { $("#details").text("Ошибка..."); } } } 9 Методы jQuery Метод Назначение get() Делает запрос методом GET post() Делает запрос методом POST getJSON() Получает данные в форматах JSON методом GET getScript() Загружает сценарий JavaScript с любого домена. После загрузки сценарий выполняется в глобальном контексте. ajax() Низкоуровневая функция, которой пользуются все остальные функции 10 Функция load() load(URL [,Отсылаемые данные] [,Функция обратного вызова]) function request(word) { var url = "/Home/Details?word=" + word; $("#details").load(url); } 11 Хелперы MVC Ajax.ActionLink – асинхронный аналог Html.ActionLink Ajax.BeginForm – асинхронный аналог Html. BeginForm 12 @Ajax.ActionLink Пример. На странице есть ссылка с текстом "Подробности". Если кликнуть по ней, вместо нее появляется сообщение, полученное от сервера. public ContentResult Details() { return Content(HomeController.Lukomorye); } Метод контроллера: @{ ViewBag.Title = "Index"; } <h2>Внеполосный запрос через Ajax.ActionLink</h2> <pre id="detailsText"> @Ajax.ActionLink("Подробности", "Details", new AjaxOptions { UpdateTargetId = "detailsText", InsertionMode = InsertionMode.Replace, HttpMethod = "GET", }) </pre> @section Scripts { @Scripts.Render("~/bundles/jqueryval") } 13 Продолжение примера Дополнительно можно задать: • режим вставки текста на страницу, • команду http, • функцию, которая обработает на клиенте событие начала запроса. <div id="details"> @Ajax.ActionLink("Подробности", "Details", new AjaxOptions { UpdateTargetId="details", InsertionMode = InsertionMode.Replace, HttpMethod = "GET", OnBegin = "begin", }) </div> JS функция на клиенте: function begin() { $("#details").html("Ну, началось..."); } 14 Как это работает Ajax-хелперы опираются на библиотеку /Scripts/jquery.unobtrusive-ajax.js, поэтому на странице должна быть ссылка на нее. Хелпер добавляет в генерируемые элементы атрибуты, имена которых начинаются с "data-". HTML5 игнорирует эти атрибуты, а функции библиотеки jquery.unobtrusive-ajax, наоборот, очень любят. <a data-ajax="true" data-ajax-mode="replace" data-ajax-update="#details" href="/Home/Details"> Подробности </a> Ссылки на JS в файле ~/App_Start/BundleConfig.cs. bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include( "~/Scripts/jquery.unobtrusive*", "~/Scripts/jquery.validate*", "~/Scripts/ajax.js" )); @Ajax.BeginForm Пример. Задать данные для поиска и показать его результат. Искать будем все объекты, поля которых начинаются с заданных строк. Модель: public class Person { public string Name { set; get; } public string Color { set; get; } public string Size { set; get; } public static IEnumerable<Person> GetPersons(Person toSearch) { Person[] persons = { new Person { Name = "Ivanov", Color = "green", Size = "huge" }, new Person { Name = "Indjukov", Color = "red", Size = "small"}, new Person { Name = "Petrov", Color = "red", Size = "small"}, }; var res = persons.Where(p => toSearch.Name == null || p.Name.StartsWith(toSearch.Name)); return res; } } 16 Продолжение примера Контроллер public class HomeController : Controller { public ActionResult Index() { return View(); } public ActionResult Search(Person person) { return PartialView(Person.GetPersons(person)); } } Представление @using (Ajax.BeginForm("Search", "Home", new AjaxOptions { InsertionMode=InsertionMode.Replace, HttpMethod="GET", OnFailure="searchFailed", LoadingElementId="ajax-loader", UpdateTargetId="searchresults", })) { <fieldset> … </fieldset> } <div id="searchresults"/> 17 Самостоятельно 1. Поместить на странице ссылку с текстом "Next Story". По нажатию на ссылку на странице должен появляться еще один анекдот (анекдотом считать любую строку символов). 18