Tag-хелпер пагинации с сортировкой и фильтрацией

Последнее обновление: 12.04.2022

В прошлой теме было рассмотрено создание ссылок для постраничного перехода. Теперь посмотрим, как мы можем заменить эти ссылки на специальный 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>
Tag-хелпер для постраничной навигации с сортировкой и фильтрацией в ASP.NET Core MVC и C#
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850