В прошлой теме было рассмотрено создание ссылок для постраничного перехода. Теперь посмотрим, как мы можем заменить эти ссылки на специальный tag-хелпер для постраничной навигации.
Добавим в проект новый класс PageLinkTagHelper:
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Mvc.Routing; using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.AspNetCore.Razor.TagHelpers; using MvcApp.Models; namespace MvcApp.TagHelpers { public class PageLinkTagHelper : TagHelper { private IUrlHelperFactory urlHelperFactory; public PageLinkTagHelper(IUrlHelperFactory helperFactory) { urlHelperFactory = helperFactory; } [ViewContext] [HtmlAttributeNotBound] public ViewContext ViewContext { get; set; } = null!; public PageViewModel? PageModel { get; set; } public string PageAction { get; set; } = ""; [HtmlAttributeName(DictionaryAttributePrefix = "page-url-")] public Dictionary<string, object> PageUrlValues { get; set; } = new(); public override void Process(TagHelperContext context, TagHelperOutput output) { if(PageModel == null) throw new Exception("PageModel is not set"); IUrlHelper urlHelper = urlHelperFactory.GetUrlHelper(ViewContext); output.TagName = "div"; // набор ссылок будет представлять список ul TagBuilder tag = new TagBuilder("ul"); tag.AddCssClass("pagination"); // формируем три ссылки - на текущую, предыдущую и следующую TagBuilder currentItem = CreateTag(PageModel.PageNumber, urlHelper); // создаем ссылку на предыдущую страницу, если она есть if (PageModel.HasPreviousPage) { TagBuilder prevItem = CreateTag(PageModel.PageNumber - 1, urlHelper); tag.InnerHtml.AppendHtml(prevItem); } tag.InnerHtml.AppendHtml(currentItem); // создаем ссылку на следующую страницу, если она есть if (PageModel.HasNextPage) { TagBuilder nextItem = CreateTag(PageModel.PageNumber + 1, urlHelper); tag.InnerHtml.AppendHtml(nextItem); } output.Content.AppendHtml(tag); } TagBuilder CreateTag(int pageNumber, IUrlHelper urlHelper) { TagBuilder item = new TagBuilder("li"); TagBuilder link = new TagBuilder("a"); if (pageNumber == PageModel?.PageNumber) { item.AddCssClass("active"); } else { PageUrlValues["page"] = pageNumber; link.Attributes["href"] = urlHelper.Action(PageAction, PageUrlValues); } item.AddCssClass("page-item"); link.AddCssClass("page-link"); link.InnerHtml.Append(pageNumber.ToString()); item.InnerHtml.AppendHtml(link); return item; } } }
Ранее уже было рассмотрено создание tag-хелпера для постраничной навигации, и в данном случае основная часть повторяется. Единственным исключением является свойство PageUrlValues:
[HtmlAttributeName(DictionaryAttributePrefix = "page-url-")] public Dictionary<string, object> PageUrlValues { get; set; } = new();
Это свойство представляет словарь Dictionary<string, object>
, в котором каждой строке будет сопоставлен некоторый объект.
Его отличительной чертой является атрибут [HtmlAttributeName(DictionaryAttributePrefix = "page-url-")]
. Он указывает, что при применении
хелпера в представлении мы сможем передать ему некоторые значения через атрибуты с префиксом "page-url-". Например:
<page-link page-url-action="Index" page-url-number="2"></page-link>
В этом случае в словаре PageUrlValues окажутся две пары значений: {"action" : "Index"} и {"number" : 2}. То есть ключи в словаре будут представлять названия атрибутов
без префикса page-url-
, а их значения - значения в этих атрибутах. Таким образом, мы можем передать в словарь PageUrlValues произвольное количество значений.
Далее все эти значения мы можем использовать, к примеру, для создания навигационных ссылок:
PageUrlValues["page"] = pageNumber; link.Attributes["href"] = urlHelper.Action(PageAction, PageUrlValues);
Применим этот хелпер в представлении:
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers @addTagHelper *, MvcApp @using MvcApp.Models @model IndexViewModel <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" /> <h1>Список пользователей</h1> <form method="get"> <label>Имя: </label> <input name="name" value="@Model.FilterViewModel.SelectedName" /> <label>Компания: </label> <select name="company" asp-items="Model.FilterViewModel.Companies"></select> <input type="submit" value="Фильтр" /> </form> <table class="table"> <tr> <th> <a asp-action="Index" asp-route-sortOrder="@(Model.SortViewModel.NameSort)" asp-route-name="@(Model.FilterViewModel.SelectedName)" asp-route-company="@(Model.FilterViewModel.SelectedCompany)">Имя</a> </th> <th> <a asp-action="Index" asp-route-sortOrder="@(Model.SortViewModel.AgeSort)" asp-route-name="@(Model.FilterViewModel.SelectedName)" asp-route-company="@(Model.FilterViewModel.SelectedCompany)">Возраст</a> </th> <th> <a asp-action="Index" asp-route-sortOrder="@(Model.SortViewModel.CompanySort)" asp-route-name="@(Model.FilterViewModel.SelectedName)" asp-route-company="@(Model.FilterViewModel.SelectedCompany)">Компания</a> </th> </tr> @foreach (User u in Model.Users) { <tr><td>@u.Name</td><td>@u.Age</td><td>@u.Company?.Name</td></tr> } </table> <page-link page-model="Model.PageViewModel" page-action="Index" page-url-name="@(Model.FilterViewModel.SelectedName)" page-url-company="@(Model.FilterViewModel.SelectedCompany)" page-url-sortorder="@(Model.SortViewModel.Current)"></page-link>