Table Sorting and Paging in an ASP.NET MVC - CodeProject

:

 

Introduction

The code in this tip shows a simple implementation of table sorting and paging in an ASP.NET MVC application.

Background

In an ASP.NET web form application, GridView server control can be used to work with a table. GridView has sorting and paging functions. Although ASP.NET MVC doesn't have any server control, similar functions can be implemented by other frameworks such as jQuery Plugins. Another alternative is to develop custom code by hand. This approach is very beneficial to learning.

Using the Code

There are several ways to implement table sorting and paging. In this simple implementation, the data source of the table is retrieved by an Ajax call to an MVC controller action. The data source is stored in a JavaScript global variable as an array for sorting and paging operation. To sort the table, sort the array and then render the table. The paging also works with the global array variable. In this design, there is only one initial server call to download the data source to the client. Then the sorting and paging are all client side JavaScript manipulation.

First, create an MVC controller and add the following functions:

public ActionResult GetAllProducts()
{
    // Get all products using entity framework and LINQ queries.
    var products = _db.Products
        .Select(p => new { p.ProductID, p.ProductName, p.QuantityPerUnit, p.UnitPrice, p.UnitsInStock })
        .OrderBy(p => p.ProductID);
    return Json(products, JsonRequestBehavior.AllowGet);
}

Second, create a view and add the following markup:

<div>
    <table id="tblProducts" class="simpleTable">
        <tr>
            <th><a id="lnkProductID" href="#">Product ID</a></th>
            <th><a id="lnkProductName" href="#">Product Name</a></th>
            <th>Quantity Per Unit</th>
            <th>Unit Price</th>
            <th>Units In Stock</th>
        </tr>
    </table>
</div>

Last, add some JavaScript code to the view page to implement sorting, paging and table display.

This is the first part of the script.

// Global variable for table data
var tableData = null;

$(document).ready(function () {
    // Populate categories when the page is loaded.
    $.getJSON('/Home/GetAllProducts', function (data) {
        // Populate table from Json data returned from server.
        PopulateTable(data, 1);
        tableData = data.slice(0);
    }).fail(function (jqXHR, textStatus, errorThrown) {
        // Ajax fail callback function.
        alert('Error getting products!');
    });

    // Link Product ID click event handler
    $('#lnkProductID').click(function (e) {
        e.preventDefault();
        if (tableData != null) {
            // Sort data
            tableData.sort(function (a, b) {
                return a.ProductID <= b.ProductID ? -1 : 1;
            });
            PopulateTable(tableData, 1);
        }
    });

    // Link Product Name click event handler
    $('#lnkProductName').click(function (e) {
        e.preventDefault();
        if (tableData != null) {
            // Sort data
            tableData.sort(function (a, b) {
                return a.ProductName <= b.ProductName ? -1 : 1;
            });
            PopulateTable(tableData, 1);
        }
    });
});

In the above code, links in table header row are used to initiate table sort. When a link is clicked, the data source is sorted by JavaScript function sort. The table is rendered by calling function PopulateTable.

This is the second part of the script for function PopulateTable.

// Populate table with pager.
// Parameters
// arrData - table data
// pageNum - table page number
function PopulateTable(arrData, pageNum) {
    var rowsPerPage = 10;
    var pages;
    var i;
    var pager = '';
    var startIndex;
    var endIndex;
    var row;
    
    $('#tblProducts tr:gt(0)').remove();
    if (arrData != null) {
        // Populate table with data in the current page.
        startIndex = (pageNum - 1) * rowsPerPage;
        endIndex = pageNum * rowsPerPage > arrData.length ? 
        arrData.length - 1 : pageNum * rowsPerPage - 1;
        for (i = startIndex; i <= endIndex; i++) {
            row = '<tr><td>' + arrData[i].ProductID + '</td>'
                  + '<td>' + arrData[i].ProductName + '</td>'
                  + '<td>' + arrData[i].QuantityPerUnit + '</td>'
                  + '<td>' + arrData[i].UnitPrice + '</td>'
                  + '<td>' + arrData[i].UnitsInStock + '</td></tr>';
            $('#tblProducts').append(row);
        }
        
        // Show pager row if there is more than one page
        pages = Math.floor(arrData.length / rowsPerPage);
        if (pages < arrData.length / rowsPerPage) {
            pages += 1;
        }
        if (pages > 1) {
            for (i = 0; i < pages; i++) {
                if (i == pageNum - 1) {
                    pager += '<span>' + (i + 1) + '</span>';
                }
                else {
                    pager += '<span><a href="#">' + (i + 1) + '</a></span>'
                }
            }
            pager = '<tr><td colspan="5" class="pagerRow">' + 
            pager + '</td></tr>';
            $('#tblProducts').append(pager);
            
            // Pager link event handler
            $('#tblProducts tr td.pagerRow a').click(function (e) {
                e.preventDefault();
                var pNum = parseInt($(this).text());
                PopulateTable(tableData, pNum);
            });
        }
    }
}

This function renders the table from data source parameter arrData. The page number to render is indicated by parameter pageNum. The function populates table with only one page. At the last row, it renders a pager. Each page number is a link except current page number. At the end of the function, the event handler of each pager link is defined which basically renders table data of the clicked page number.

Points of Interest

JavaScript library jQuery can greatly simplify HTML manipulation. It is an amazing framework!