Snow
Snow

Reputation: 87

Fix pagination in ASP.NET Core

I am trying to fixed pagination in my project. But I do not get the correct result. I want to make this result 123 ... 12

PS I study with book Adam Freeman Pro ASP.NET Core MVC 2. Project in GitHub https://github.com/JasARGHUN/StoreProject-

enter image description here

Pagin model PagingInfo.cs:

public class PagingInfo
    { public int TotalItems { get; set; }
        public int ItemsPerPage { get; set; }
        public int CurrentPage { get; set; }

        public int TotalPages =>
            (int)Math.Ceiling((decimal)TotalItems / ItemsPerPage); }

Descriptor class PageLinkTagHelper.cs

[HtmlTargetElement("div", Attributes = "page-model")]
    public class PageLinkTagHelper : TagHelper
    {
        private IUrlHelperFactory urlHelperFactory;

        public PageLinkTagHelper(IUrlHelperFactory helperFactory)
        {
            urlHelperFactory = helperFactory;
        }
        [ViewContext]
        [HtmlAttributeNotBound]
        public ViewContext ViewContext { get; set; }
        public PagingInfo PageModel { get; set; }
        public string PageAction { get; set; }

        [HtmlAttributeName(DictionaryAttributePrefix = "page-url-")]
        public Dictionary<string, object> PageUrlValues { get; set; } = new Dictionary<string, object>();

        public bool PageClassesEnabled { get; set; } = false;
        public string PageClass { get; set; }
        public string PageClassNormal { get; set; }
        public string PageClassSelected { get; set; }

        public override void Process(TagHelperContext context, TagHelperOutput output)
        {
            IUrlHelper urlHelper = urlHelperFactory.GetUrlHelper(ViewContext);
            TagBuilder result = new TagBuilder("div");
            for (int i = 1; i <= PageModel.TotalPages; i++)
            {
                TagBuilder tag = new TagBuilder("a");
                PageUrlValues["productPage"] = i;
                tag.Attributes["href"] = urlHelper.Action(PageAction, PageUrlValues);
                if (PageClassesEnabled)
                {
                    tag.AddCssClass(PageClass);
                    tag.AddCssClass(i == PageModel.CurrentPage
                        ? PageClassSelected : PageClassNormal);
                }
                tag.InnerHtml.Append(i.ToString());
                result.InnerHtml.AppendHtml(tag);
            }
            output.Content.AppendHtml(result.InnerHtml);
        }
    }

Pagination view model ProductsListViewModel

public class ProductsListViewModel
    {
        public IEnumerable<Product> Products { get; set; }
        public PagingInfo PagingInfo { get; set; }
        public string CurrentCategory { get; set; }
    }

Controller ProductController.cs

public class ProductController : Controller
    {
        private IProductRepository _repository;
        public int PageSize = 4;

        public ProductController(IProductRepository repository)
        {
            _repository = repository;
        }

        public ViewResult List(string category, int productPage = 1) =>
            View(new ProductsListViewModel
            {
                Products = _repository.Products
                .Where(p => category == null || p.Category == category)
                .OrderBy(p => p.ProductID)
                .Skip((productPage - 1) * PageSize)
                .Take(PageSize),
                PagingInfo = new PagingInfo
                {
                    CurrentPage = productPage,
                    ItemsPerPage = PageSize,
                    TotalItems = category == null ?
                    _repository.Products.Count() :
                    _repository.Products.Where(e =>
                    e.Category == category).Count()
                },
                CurrentCategory = category
            });}

View List.cshtml

@model ProductsListViewModel
@foreach (var p in Model.Products)
{
    @await Html.PartialAsync("ProductSummary", p);
}

<div page-model="@Model.PagingInfo" page-action="List" page-classes-enabled="true"
     page-class="btn" page-class-normal="btn-secondary"
     page-class-selected="btn-primary" page-url-category="@Model.CurrentCategory"
     class="btn-group pull-right m-1"></div>

Navigation menu Navigation.cshtml

@model IEnumerable<string>

<a class="btn btn-block btn-secondary border mb-1"
   asp-action="List"
   asp-controller="Product"
   asp-route-category="">Home</a>

<div>
    @foreach (string category in Model)
    {
        <a class="btn btn-sm btn-block border @(category == ViewBag.SelectedCategory ? "btn-info": "btn-light")"
           asp-action="List"
           asp-controller="Product"
           asp-route-category="@category"
           asp-route-productPage="1">@category</a>
    }
</div>

I want to do something like this pagination enter image description here

Upvotes: 0

Views: 2112

Answers (3)

Jhon
Jhon

Reputation: 1

controller/

    public IActionResult Index(int page=1)
    {

        ViewBag.Page = page;
        ViewBag.TotalPage = (int)Math.Ceiling(_context.Books.Include(x => x.Author).Include(x => x.Genre).Count() / 2d);
        var data = _context.Books.Include(x => x.Author).Include(x => x.Genre).Skip((page - 1) * 2).Take(2).ToList();

        return View(data);
    }

cshtml/

 <div aria-label="Page navigation example">
                    <ul class="pagination">
                        <li class="page-item @(page==1?"disabled":"")"><a class="page-link" asp-action="index" asp-route-page="1"><<</a></li>
                        <li class="page-item @(page==1?"disabled":"")"><a class="page-link" asp-action="index" asp-route-page="@(page-1)"><</a></li>
                        @if (page == 1)
                        {
                            for (int i = page; i <= page + 2; i++)
                            {
                                <li class="page-item @(page==i?"active":"")"><a class="page-link" asp-action="index" asp-route-page="@i">@i</a></li>

                            }
                        }
                        else if (page == totalPages)
                        {
                            for (int i = page - 2; i <= page; i++)
                            {
                                <li class="page-item @(page==i?"active":"")"><a class="page-link" asp-action="index" asp-route-page="@i">@i</a></li>

                            }
                        }
                        else
                        {
                            for (int i = page - 1; i <= page + 1; i++)
                            {
                                <li class="page-item @(page==i?"active":"")"><a class="page-link" asp-action="index" asp-route-page="@i">@i</a></li>

                            }
                        }
                        <li class="page-item @(page==totalPages?"disabled":"")"><a class="page-link" asp-action="index" asp-route-page="@(page+1)">></a></li>
                        <li class="page-item @(page==totalPages?"disabled":"")"><a class="page-link" asp-action="index" asp-route-page="@totalPages">>></a></li>

                    </ul>
                </div>

Upvotes: 0

Snow
Snow

Reputation: 87

Ok, i tried and resolv my trouble, updated Controller, TagHelper class and View. Maybe someone will come in handy.

Controller:

public async Task<IActionResult> List(string category, int page = 1)
        {
            IQueryable<Product> source = _repository.Products.Where(p => category == null || p.Category == category)
                .OrderBy(p => p.ProductID);
            var count = await source.CountAsync();
            var items = await source.Skip((page - 1) * pageSize).Take(pageSize).ToListAsync();

            PagingInfo pagingInfo = new PagingInfo(count, page, pageSize);
            ProductsListViewModel productsListView = new ProductsListViewModel
            {
                PagingInfo = pagingInfo,
                Products = items
            };

            return View(productsListView);}

View:

<h3><page-link page-model="Model.PagingInfo" page-action="List"></page-link></h3>

TagHelper class:

public class PageLinkTagHelper : TagHelper
    {
        private IUrlHelperFactory urlHelperFactory;
        public PageLinkTagHelper(IUrlHelperFactory helperFactory)
        {
            urlHelperFactory = helperFactory;
        }
        [ViewContext]
        [HtmlAttributeNotBound]
        public ViewContext ViewContext { get; set; }
        public PagingInfo PageModel { get; set; }
        public string PageAction { get; set; }

        public override void Process(TagHelperContext context, TagHelperOutput output)
        {
            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 == this.PageModel.PageNumber)
            {
                item.AddCssClass("active");
            }
            else
            {
                link.Attributes["href"] = urlHelper.Action(PageAction, new { page = pageNumber });
            }
            link.InnerHtml.Append(pageNumber.ToString());
            item.InnerHtml.AppendHtml(link);
            return item;
        }
    }
}

Upvotes: 2

mattfullerdev
mattfullerdev

Reputation: 129

Change your for loop

for (PageModel.CurrentPage; i <= PageModel.CurrentPage + 2; i++)

That will give you 3 results based on the current page.

Then you can add a button the first and the last page on either end of the html.

There's probably a more elegant approach but that should work.

Upvotes: 0

Related Questions