Pull to refresh

ASP .NET MVC 3. Ajax.ActionLink в виде картинки на примере добавления в избранное звездочкой на habrahabr.ru

Reading time 8 min
Views 17K
Данная статья посвящается созданию ссылки картинкой с использованием хелпер метода Ajax.ActionLink, а точнее Extension методу Ajax.ActionImageLink, который мы и будем создавать.

Для начала краткие сведения о Ajax, ASP .NET MVC 3 и их совместном использовании.

AJAX (Asynchronous Javascript and XML — «асинхронный JavaScript и XML») — подход к построению интерактивных пользовательских интерфейсов веб-приложений, заключающийся в «фоновом» обмене данными браузера с веб-сервером. В результате, при обновлении данных, веб-страница не перезагружается полностью, и веб-приложения становятся более быстрыми и удобными.

ASP .NET MVC — фреймворк для создания веб-приложений, который реализует шаблон Model-view-controller (MVC) на базе технологии ASP .NET.

Для использования AJAX в ASP .NET MVC 3 существует несколько Action методов, но нас интересует Ajax.ActionLink, поэтому о нём поподробнее:

Ajax.ActionLink


Ajax.ActionLink — метод, возвращающий сформированную в зависимости от передаваемых параметров ссылку, клик по которой отправит асинхронный запрос на сервер и определит дальнейшее поведение страницы.
Всего существует 12 вариантов перегрузки этого метода,- ниже рассмотрены входные параметры, которые могут быть переданы для его использования:
  • this AjaxHelper ajaxHelper — класс, предоставляющий поддержку отображения HTML в AJAX сценариях;
  • string linkText — текст ссылки;
  • string actionName — название серверного Action метода контроллера, куда поступит запрос на обработку;
  • string controllerName — название контроллера, куда поступит запрос в поисках Action метода для обработки;
  • string protocol — протокол, по которому будет отправлен запрос (например «http» или «https»);
  • string hostName — доменное имя (например «habrahabr.ru»);
  • string fragment — наименование фрагмента, которое добавится после # в конец URL'a;
  • RouteValueDictionary / object routeValues — параметры, передаваемые на сервер в строке URL'a;
  • AjaxOptions ajaxOptions — опции выполнения асинхронного запроса
    • string Confirm — сообщение, которое отобразится перед отправкой данных на сервер с требованием подтверждения действий пользователем;
    • string HttpMethod — метод, которым отправлять данные на сервер («POST», «GET»);
    • InsertionMode InsertionMode — свойство, указывающее как обновлять DOM HTML страницы полученными данными («InsertAfter», «InsertBefore», or «Replace»);
    • string LoadingElementId — id HTML элемента, который отображается пока выполняется асинхронный запрос (от OnBegin до OnComplete), например, это может быть ajaxLoader.gif;
    • string OnBegin — название javascript функции, которая будет выполнена до отправки запроса;
    • string OnComplete — название javascript функции, которая будет выполнена после того, как данные поступили от сервера, но страница еще не была обновлена;
    • string OnFailure — название javascript функции, которая выполнится в случае ошибки обновления страницы. Например, можно перехватить код ошибки, который вернёт сервер;
    • string OnSuccess — название javascript функции, которая будет выполнена после успешного получения данных от сервера и обновления страницы;
    • string UpdateTargetId — id HTML элемента, который будет обновлён полученными данными от сервера (например HTML разметкой или строкой обновить div или вывести сообщение в span);
    • string Url — URL адрес, на который отправить запрос;
  • IDictionary<string, Object> htmlAttributes — коллекция ключ-значение, в которой можно указать добавляемые к сгенерированной HTML разметке аттрибуты (например new { class = «add» }).

Для использования возможностей Ajax в проекте MVC 3 нам требуется подключить следующие файлы, которые, по умолчанию, находятся в папке /Scripts:
  • jquery-1.4.4.js
  • jquery.unobtrusive-ajax.min.js


Постановка задачи


Требуется создать ссылку в виде изображения (в нашем случае звездочки), клик по которой вызовет асинхронный запрос на сервер, и после получения ответа, выполнится её обновление (смена изображения, всплывающей подсказки):

image

Рассмотрев возможности, которые предоставляет нам Microsoft по работе с Ajax хелпером ActionLink, приходим к выводу, что без велосипеда здесь не обойтись их не достаточно, поэтому нам потребуется наш собственный хелпер. Приступим.

1. Создаем пустой ASP .NET MVC 3 проект


image

Во View engine указываем Razor.

image

2. Добавляем HomeController и представление для метода Index


image

Выбираем ~/Views/Shared/_Layout.cshtml как мастер пейдж для нашего представления

image

И так, теперь нам требуется создать Extension метод для нашего Ajax хелпера.

3. Создаем Extension метод Ajax.ActionImageLink


Добавляем в корень проекта папку Core и в неё новый статический класс Extensions.cs

image

Подробнее о создании расширяющих методов можно прочитать здесь.

Переходим непосредственно к созданию расширяющего метода. И так, за основу нашей ссылки с изображением возьмём HTML разметку и стили habrahabr.ru, тогда содержимое контейнера будет представлено двумя состояниями:
<div class="favourite">
    <a class="add" title="Добавить в избранное" href="#"></a>
</div>

<div class="favourite">
    <a class="remove" title="Удалить из избранного" href="#"></a>
</div>


Отсекая всё лишнее, приходим к тому, что контейнером (объектом для изменения — UpdateTargetId) будет являться div, а возвращать наш метод должен будет HTML разметку в виде ссылки с изменяющимся классом и title'ом.

*Тут автор впервые задумался, и понял, что всё это решается и без расширяющих методов посредством следующего кода:
@Ajax.ActionLink(" ", "Hello", "World", null, new AjaxOptions() { }, 
new { 
@title= Model.inFavourite? "Добавить в избранное" : "Удалить из избранного", 
@class = Model.inFavourite? "add" : "remove" 
})

но решив, что так будет слишком просто, и немного смекнув, усложнил себе задачу.*

Отсекая всё лишнее… Добавляя лишнее, приходим к тому, что контейнером (объектом для изменения — UpdateTargetId) будет являться div, а возвращать наш метод должен будет HTML разметку в виде ссылки, содержащей в себе изображение с изменяющимся title'ом и путём до картинки.
<div id="favourite">
    <a href="/Home/AddOrRemoveFavourite">
        <img src="/Content/images/star-off.png" title="Добавить в избранное" />
    </a>
</div>

<div id="favourite">
    <a href="/Home/AddOrRemoveFavourite">
        <img src="/Content/images/star-on.png" title="Удалить из избранного" />
    </a>
</div>

Примечание:
Можно использовать разные методы для добавления/удаления записи в избранное, но в рамках этой статьи метод будет использоваться один — AddOrRemoveFavourite.
И так, каркас нашего расширяющего метода представлен ниже:
        public static IHtmlString ImageActionLink(this AjaxHelper helper, string actionName, bool inFavourite, AjaxOptions ajaxOptions)
        {
        }

Входными параметрами являются:
  1. actionName — наименование метода контроллера (AddOrRemoveFavourite);
  2. inFavourite — признак того, добавлена ли запись уже в избранное;
  3. ajaxOptions — параметры выполнения запроса.

Для создания HTML разметки нашего изображения воспользуемся классом TagBuilder:
var builder = new TagBuilder("img");
builder.MergeAttribute("src", String.Format("/Content/images/star-{0}.png", inFavourite ? "on" : "off"));
builder.MergeAttribute("title", inFavourite ? "Удалить из избранного" : "Добавить в избранное");

Для создания ссылки используем стандартный метод Ajax.ActionLink:
var link = helper.ActionLink("[replaceme]", actionName, routeValues, ajaxOptions).ToHtmlString();

и затем добавим замену текста ссылки, на содержимое нашего HTML элемента img:
return new MvcHtmlString(link.Replace("[replaceme]", builder.ToString(TagRenderMode.SelfClosing)));

В результате, наш класс Extensions.cs примет вид:
    public static class Extensions
    {
        public static IHtmlString ImageActionLink(this AjaxHelper helper, string actionName, bool inFavourite, AjaxOptions ajaxOptions)
        {
            var builder = new TagBuilder("img");
            builder.MergeAttribute("src", String.Format("/Content/images/star-{0}.png", inFavourite ? "on" : "off"));
            builder.MergeAttribute("title", inFavourite ? "Удалить из избранного" : "Добавить в избранное");

            var link = helper.ActionLink("[replaceme]", actionName, inFavourite, ajaxOptions).ToHtmlString();
            return new MvcHtmlString(link.Replace("[replaceme]", builder.ToString(TagRenderMode.SelfClosing)));
        }
    }

Если добавить в представление вызов нашего расширяющего метода (предварительно указав директиву @using MVC3_AjaxActionImageLink.Core), то будет сформирована следующая HTML разметка:
<a data-ajax="true" data-ajax-mode="replace" data-ajax-update="#favourite" ref="/Home/AddOrRemoveFavourite">
    <img src="/Content/images/star-on.png" title="Удалить из избранного" />
</a>

или
<a data-ajax="true" data-ajax-mode="replace" data-ajax-update="#favourite" href="/Home/AddOrRemoveFavourite">
    <img src="/Content/images/star-off.png" title="Добавить в избранное" />
</a>

Осталось добавить лишь div, картинки звездочек, вызов метода в представлении и сам метод AddOrRemoveFavourite, однако на последнем хотелось бы остановиться поподробнее.

4. Добавление метода AddOrRemoveFavourite в контроллер


В общем виде, метод, который обрабатывает асинхронный запрос, возвращает значение, будь то строка, число, JSON данные и пр., но в нашем случае, нам потребуется вернуть HTML разметку нового элемента, который генерирует наш расширяющий метод. Увы (или к счастью), в ASP .NET MVC 3 отсутствует возможность вызова нашего расширяющего метода на стороне сервера (в методе контроллера) и поэтому сгенерировать разметку без дублирования самого кода в методе контроллера у нас не получится (иначе, будет нарушен один из основополагающих принципов MVC- DRY).

Однако, из метода контроллера мы можем вернуть вызов Partial View, который инициирует вызов нашего расширяющего метода, который в свою очередь вернёт HTML разметку.

Приступим.

4.1. Добавляем Partial View с вызовом расширяющего метода


Добавляем в папку Views папку Partial. В Partial добавляем папку Favourites.
В папку Favourites добавляем View, выбирая галкой Create as partial view и указывая наименование AddOrRemoveFavourites_PartialView

image

В содержимое добавленного Partial View добавляем директивы:
@using MVC3_AjaxActionImageLink.Core
@Model bool

и сам вызов нашего метода:
@Ajax.ImageActionLink("AddOrRemoveFavourite", (bool)Model, new AjaxOptions() { UpdateTargetId = "favourite" });

Примечание. Для упрощения деталей моделью в данной статье будет являться статическая переменная типа bool.

Содержимое же Index.cshtml теперь поручает вызов расширяющего метода Partial View и выглядит следующим образом:
@using MVC3_AjaxActionImageLink.Core
@model bool
@{
    ViewBag.Title = "Index";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>Index</h2>

<div id="favourite">
    @{ Html.RenderPartial("/Views/Partial/Favourites/AddOrRemoveFavourites_PartialView.cshtml", Model); }
</div>


4.2. Добавляем метод обработки асинхронного запроса AddOrRemoveFavourite в контроллер и связываем с моделью


Для того, чтобы вернуть наш Partial View, требуется указать в return вызов метода PartialView, передав первым параметром путь. Кроме этого, так как мы сохраняем состояние примитивным способом через статическую bool переменную, мы передадим её как модель в обе наши View. Конечный вариант нашего класса HomeController.cs представлен ниже:
    public class HomeController : Controller
    {
        public static bool inFavourite = true;
        public ActionResult AddOrRemoveFavourite()
        {
            if (Request.IsAjaxRequest())
            {
                inFavourite = !inFavourite; // TODO: Add or remove favourite

                return PartialView("/Views/Partial/Favourites/AddOrRemoveFavourites_PartialView.cshtml", inFavourite);
            }
            return View();
        }

        public ActionResult Index()
        {
            // TODO: Check, if row is already in favourites
            return View(inFavourite);
        }
    }


5. Что осталось?


Завершающим этапом будет добавление папки images с картинками star-off.png и star-on.png, а так же подключение скрипта для работы с AJAX в ASP .NET MVC 3:
<script src="../../Scripts/jquery.unobtrusive-ajax.min.js" type="text/javascript"></script>

Пробуем.

image

кликаем

image

Заключение


image

Итак, что же мы всё таки в данной статье сделали и усвоили:
  • Рассмотрели возможность использования AJAX в ASP .NET MVC 3 с использованием метода Ajax.ActionLink
  • Получили представление о создании собственных расширяющих методов и их использовании
  • Узнали, как вернуть из AJAX запроса сгенерированную HTML разметку посредством вызова Html хелпера
  • Не нарушили принцип DRY


Примечание


Наименование метода и принцип построения ссылки в виде изображения был взят из проекта Stephen Walthe's Contact manger project
Tags:
Hubs:
+26
Comments 8
Comments Comments 8

Articles