C# cơ bản .NET Core

Tạo HTML phân trang sử dụng BootStrap trong ASP.NET Core

Khi hiện thị một danh sách dữ liệu dài, có nhu cầu chia nhỏ thành từng trang ngắn - cho thêm vào điều hướng để người dùng lặt trang - chuyển trang.

Ta sẽ xây dựng một Partial hiện thị thanh điều hướng này theo dữ liệu gửi đến. Giả thiết đầu vào phát sinh HTML sẽ gồm các dữ liệu sau:

  • countPages - số nguyên - là tổng số trang của dữ liệu
  • currentPage - số nguyên - trang hiện tại
  • generateUrl - là một delegate - Func<int p, string url> nhận thao số p là chỉ mục trang trả về chuỗi là Url của trang. Ví dụ p = 5 trả về /product/?page=5 - delegate này phát sinh Url theo Page, Controller ... như thế nào là do bạn xây dựng khi truyền tham số. Xem thêm Action và Func

Nội dung của Partial __Paging.cshtml sẽ lưu ở Pages/Shared/_Paging.cshtml

@* 
    Model:
      - currentPage:int - Trang hiện tại
      - countPages:int - tổng số trang
      - generateUrl:delegate Func<int?, string> trả về URL tương ứng với trang p (1,2,3 ...)
*@

@model dynamic
@{
    int currentPage  = Model.currentPage;
    int countPages   = Model.countPages;
    var generateUrl  = Model.generateUrl;
    
    if (currentPage > countPages) 
      currentPage = countPages;

    if (countPages <= 1) return;
    

    int? preview = null;
    int? next = null;

    if (currentPage > 1)
        preview = currentPage - 1;

    if (currentPage < countPages)
        next = currentPage + 1;

    // Các trang hiện thị trong điều hướng
    List<int> pagesRanges = new List<int>();    

        
    int delta      = 5;             // Số trang mở rộng về mỗi bên trang hiện tại     
    int remain     = delta * 2;     // Số trang hai bên trang hiện tại

    pagesRanges.Add(currentPage);
    // Các trang phát triển về hai bên trang hiện tại
    for (int i = 1; i <= delta; i++)
    {
        if (currentPage + i  <= countPages) {
            pagesRanges.Add(currentPage + i); 
            remain --;
        }
               
        if (currentPage - i >= 1) {
            pagesRanges.Insert(0, currentPage - i);
            remain --;
        }
            
    }    
    // Xử lý thêm vào các trang cho đủ remain 
    //(xảy ra ở đầu mút của khoảng trang không đủ trang chèn  vào)
    if (remain > 0) {
        if (pagesRanges[0] == 1) {
            for (int i = 1; i <= remain; i++)
            {
                if (pagesRanges.Last() + 1 <= countPages) {
                    pagesRanges.Add(pagesRanges.Last() + 1);
                }
            }
        }
        else {
            for (int i = 1; i <= remain; i++)
            {
                if (pagesRanges.First() - 1 > 1) {
                    pagesRanges.Insert(0, pagesRanges.First() - 1);
                }
            }
        }
    }

}

@* PHÁT SINH HTML*@

<ul class="pagination">
    <!-- Previous page link -->
    @if (preview != null)
    {
        <li class="page-item">
            <a class="page-link" href="@generateUrl(preview)">Trang trước</a>
        </li>
    }
    else
    {
        <li class="page-item disabled">
            <a class="page-link" href="#" tabindex="-1" aria-disabled="true">Trang trước</a>
        </li>
    }
      
    <!-- Numbered page links -->
    @foreach (var pageitem in pagesRanges)
    {
        if (pageitem != currentPage) {
            <li class="page-item">
                <a class="page-link" href="@generateUrl(pageitem)">
                    @pageitem
                </a>
            </li>
        }   
        else 
        {
            <li class="page-item active" aria-current="page">
                <a class="page-link" href="#">@pageitem <span class="sr-only">(current)</span></a>
            </li>
        }
    }


    <!-- Next page link -->
    @if (next != null)
    {
        <li class="page-item">
            <a class="page-link" href="@generateUrl(next)">Trang sau</a>
        </li>
    }
    else 
    {
        <li class="page-item disabled">
            <a class="page-link" href="#" tabindex="-1" aria-disabled="true">Trang sau</a>
        </li>
    }
</ul>

Bất kỳ khi nào muốn chèn HTML phân trang bạn có thể chèn bằng cách dùng

<partial name="_Paging" model="@datapaging" />

Trong đó datapagingkiểu dynamic chứa các thông số cần truyền vào partial gồm: currentPage, currentPage, generateUrl

Ví dụ chạy thử trong một Razor Page:

@{
    // xây dựng Func phát sinh Url từ page ./Index
    Func<int?,string> generateUrl = (int? _pagenumber)  => {
        return Url.Page("./User", new {pageNumber = _pagenumber});
    };

    var datapaging = new {
        currentPage = 2,    // trang hiện tại
        countPages  = 20,   // tổng  số trang 
        generateUrl =  generateUrl
    };

}
<partial name="_Paging" model="@datapaging" />

Kết quả như sau:

role

Khi sử dụng thực tế các tham số countPages, currentPage được truyền đến từ PageModel, Controller thường là kết quả tính toán dựa trên truy vấn số lượng phần tử cần hiện thị từ một bảng dữ liệu

Kỹ thuật truy vấn LINQ lấy số phần tử từng trang

Khi bạn viết một câu truy vấn LINQ ví dụ:

var products = from p in dbproducts select p;

Trong đó dbproducts là nguồn cấp dữ liệu nào đó, ví dụ DbSet trong DbContext ..., thì products là một đối tượng kiểu IQueryable, bạn có thể bỏ qua một số phần từ đầu chỉ lấy các phần tử sau bằng cách dùng Skip(n), bạn chỉ lấy ra một số phần tử bằng cách dùng Take(n)

Ví dụ, bỏ qua 100 phần tử đầu tiên, tiếp theo chỉ lấy ra 10 phần tử thì bạn viết

var pros = products.Skip(100).Take(10);

Bạn có thể áp dụng kỹ thật này để lấy ra số phần tử theo từng trang

var products = from p in dbproducts select p;

// Lấy tổng số dòng dữ liệu
var totalItems = products.Count();
// Tính số trang hiện thị (mỗi trang hiện thị ITEMS_PER_PAGE mục do bạn cấu hình = 10, 20 ...)
int totalPages = (int)Math.Ceiling((double)totalItems / ITEMS_PER_PAGE);
// Lấy phần tử trong  hang hiện tại (pageNumber là trang hiện tại - thường Binding từ route)
var pros = products.Skip(ITEMS_PER_PAGE * (pageNumber - 1)).Take(ITEMS_PER_PAGE).ToList();

Code trên có thể viết trong Controller, PageModel ... bạn có được trang hiện tại, tổng số trang, các phần tử của trang hiện tại để chuyển cho View - hiện thị phần tử và tạo HTML Paging


Đăng ký nhận bài viết mới