Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Implementing Static Pagination for MVC Table Data Using jQuery AJAX

Tech Jun 8 1

Creating a Pagination Helper Class

First, let's create a pagination helper class in the System.Web.Mvc namespace. This class will generate pagination controls for our MVC application.

/// <summary>
/// Pagination helper for MVC applications
/// </summary>
/// <param name="htmlHelper">HTML helper instance</param>
/// <param name="baseUrl">Base URL for pagination links</param>
/// <param name="targetContainerId">ID of the container to load content into</param>
/// <param name="searchTerm">Search/filter term</param>
/// <param name="sortColumn">Column to sort by</param>
/// <param name="sortDirection">Sort direction (ASC or DESC), defaults to DESC</param>
/// <param name="totalItems">Total number of records</param>
/// <param name="currentPage">Current page number, defaults to 1</param>
/// <param name="itemsPerPage">Number of items per page, defaults to 20</param>
/// <returns>MvcHtmlString containing pagination controls</returns>
public static MvcHtmlString Pagination(this HtmlHelper htmlHelper, string baseUrl, string targetContainerId, string searchTerm, string sortColumn, string sortDirection, int totalItems, int? currentPage = 1, int? itemsPerPage = 20)
{
    StringBuilder paginationBuilder = new StringBuilder();
    int pageIndex = currentPage ?? 1;
    int pageSize = itemsPerPage ?? 20;

    int visiblePages = 10;
    int startPage = pageIndex % visiblePages == 0 ? (pageIndex - visiblePages) : pageIndex - (pageIndex % visiblePages);

    int totalPages = (totalItems + pageSize - 1) / pageSize;

    baseUrl = baseUrl.TrimStart('/');
    baseUrl = "/" + baseUrl;

    if (string.IsNullOrWhiteSpace(sortDirection))
    {
        sortDirection = "DESC";
    }

    // First page link
    if (pageIndex > visiblePages)
        paginationBuilder.AppendLine(String.Format("<a href='#' onclick=loadPageData('{0}','{1}','{2}','{3}','{4}','{5}','{6}') >首页</a>", targetContainerId, 1, pageSize, baseUrl, sortColumn, sortDirection, searchTerm));

    // Previous page link
    if (pageIndex > 1)
    {
        int prevPage = pageIndex - 1;
        paginationBuilder.AppendLine(String.Format("<a href='#' onclick=loadPageData('{0}','{1}','{2}','{3}','{4}','{5}','{6}') >上一页</a>", targetContainerId, prevPage, pageSize, baseUrl, sortColumn, sortDirection, searchTerm));
    }

    // Ellipsis for previous pages
    if (pageIndex - visiblePages > 0)
    {
        paginationBuilder.AppendLine(String.Format("<a href='#' onclick=loadPageData('{0}','{1}','{2}','{3}','{4}','{5}','{6}') >...</a>", targetContainerId, (startPage + 1), pageSize, baseUrl, sortColumn, sortDirection, searchTerm));
    }

    // Page numbers
    for (int i = startPage; i < totalPages && i < startPage + visiblePages; i++)
    {
        int pageNum = i + 1;
        if (pageIndex == pageNum)
        {
            paginationBuilder.AppendLine("<span class=\"current\">" + pageNum + "</span>");
        }
        else
        {
            paginationBuilder.AppendLine(String.Format("<a href='#' onclick=loadPageData('{0}','{1}','{2}','{3}','{4}','{5}','{6}') >{1}</a>", targetContainerId, pageNum, pageSize, baseUrl, sortColumn, sortDirection, searchTerm));
        }
    }

    // Ellipsis for next pages
    if (pageIndex + visiblePages <= totalPages - 1)
    {
        paginationBuilder.AppendLine(String.Format("<a href='#' onclick=loadPageData('{0}','{1}','{2}','{3}','{4}','{5}','{6}') >...</a>", targetContainerId, (startPage + visiblePages + 1), pageSize, baseUrl, sortColumn, sortDirection, searchTerm));
    }

    // Next page link
    if (pageIndex < totalPages)
    {
        paginationBuilder.AppendLine(String.Format("<a href='#'  onclick=loadPageData('{0}','{1}','{2}','{3}','{4}','{5}','{6}') >下一页</a>", targetContainerId, pageIndex + 1, pageSize, baseUrl, sortColumn, sortDirection, searchTerm));
    }
    
    // Last page link
    if (totalPages > visiblePages && pageIndex < totalPages)
    {
        paginationBuilder.AppendLine(String.Format("<a href='#' onclick=loadPageData('{0}','{1}','{2}','{3}','{4}','{5}','{6}') >尾页</a>", targetContainerId, totalPages, pageSize, baseUrl, sortColumn, sortDirection, searchTerm));
    }

    return new MvcHtmlString(paginationBuilder.ToString());
}

Remember to place this class in the System.Web.Mvc namespace:

namespace System.Web.Mvc
{
    public static class PaginationHelper
    {
        // Add the pagination method here
    }
}

Implementing AJAX Pagination with JavaScript

Next, let's create a JavaScript function to handle the AJAX requests for pagination:

// divId: ID of the container to load content into
// pageNum: Current page number
// itemsPerPage: Number of items to display per page
// baseUrl: Base URL for the pagination request
// sortColumn: Column to sort by
// sortDirection: Sort direction (ASC or DESC)
// searchValue: Search/filter term
function loadPageData(divId, pageNum, itemsPerPage, baseUrl, sortColumn, sortDirection, searchValue) {
    if (searchValue === undefined) {
        searchValue = "";
    }
    
    var requestUrl = baseUrl + "?searchTerm=" + searchValue + "&pageNum=" + pageNum + "&itemsPerPage=" + itemsPerPage + "&sortColumn=" + sortColumn + "&sortDirection=" + sortDirection;
    var targetElement = "#" + divId;
    
    $.ajax({
        url: requestUrl,
        async: false,
        success: function (response) {
            $(targetElement).html(response);
        },
        error: function (error) {
            alert("Error loading pagination data");
        }
    });
}

Setting Up MVC Views for Pagination

Now, let's set up the views to use our pagination functionality. We'll need two views: a main container view and a data view.

Main Container View

This view will render the data view and contain the pagination controls:

<div id="ContentContainer" style="width: 100%">  
 @{  
    Html.RenderAction("DataList");  
 }  
</div>

<div class="pagination-controls">  
    @Html.Pagination("/Admin/DataList", "ContentContainer", "", sortColumn, sortDirection, totalRecords, currentPage, pageSize)  
</div>

The pagination controls use the CSS class "pagination-controls" where the current page is styled with "span.current".

Data View

This view displays the actual data and is called by the main container view:

@model IEnumerable<YourModel>

<table>
    <thead>
        <tr>
            <th>@Html.ActionLink("Column1", "DataList", new { sortColumn = "Column1", sortDirection = sortDirection, searchTerm = searchTerm })</th>
            <th>@Html.ActionLink("Column2", "DataList", new { sortColumn = "Column2", sortDirection = sortDirection, searchTerm = searchTerm })</th>
            <!-- Add more columns as needed -->
        </tr>
    </thead>
    <tbody>
        @foreach (var item in Model)
        {
            <tr>
                <td>@item.Property1</td>
                <td>@item.Property2</td>
                <!-- Add more properties as needed -->
            </tr>
        }
    </tbody>
</table>

Server-Side Pagination with Stored Procedure

For improved performance with large datasets, consider implementing server-side pagination using a stored procedure:

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

CREATE PROCEDURE [dbo].[PaginatedData]       
    @sqlStatement NVARCHAR(4000), -- SQL statement to execute    
    @requestedPage INT = 1, -- Page number to display    
    @itemsPerPage INT = 10, -- Number of items per page    
    @totalRecords INT = 0 OUTPUT, -- Total number of records    
    @totalPages INT = 0 OUTPUT -- Total number of pages    
AS    
SET NOCOUNT ON    
    DECLARE @cursorHandle INT    
    
    EXEC sp_cursoropen @cursorHandle OUTPUT, @sqlStatement, @scrollopt = 1, @ccopt = 1, @rowcount = @totalPages OUTPUT    
    
    SELECT @totalRecords = @totalPages, @totalPages = CEILING(1.0 * @totalPages / @itemsPerPage)        
    , @requestedPage = (@requestedPage - 1) * @itemsPerPage + 1        
    SELECT @totalRecords AS totalRecords, @totalPages AS totalPages, @requestedPage AS currentPage    
    EXEC sp_cursorfetch @cursorHandle, 16, @requestedPage, @itemsPerPage        
    EXEC sp_cursorclose @cursorHandle

This stored procedure returns the total number of records, total pages, and the requested page of data, making it efficient for large datasets.

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.