ASP.NET MVC simple server-side ajax paging using jQuery

It’s always important to page your data on the server side so that you are only hitting the database to get the page you currently need, rather than getting all the results and paging on the client. In this post I’ll explain how to perform simple ajax paging on the server side using ASP.NET MVC 3.

Download source

First of all I’ve created an empty MVC 3 solution and added a Person object. I’ve used Entity Framework Code First and created a simple add form to populate my People collection. I have then added a partial view to my index page to display the people in an HTML table.

First I’m going to limit by query to bring me back the first page of results, and render paging links for the number of pages I require. To help with this I’ve created a helper class called PagedData which will hold the information about the paging as well as the page of data. Initially I’ve just added the list of data and the total number of pages:

public class PagedData<T> where T : class
{
    public IEnumerable<T> Data { get; set; }
    public int NumberOfPages { get; set; }
}

I’ve changed my Index action method to use this object and populate its properties and added a constant to my controller for the page size:

    public const int PageSize = 5;

    public ActionResult Index()
    {
        var people = new PagedData<Person>();

        using (var ctx = new AjaxPagingContext())
        {
            people.Data = ctx.People.OrderBy(p => p.Surname).Take(PageSize).ToList();
            people.NumberOfPages = Convert.ToInt32(Math.Ceiling((double)ctx.People.Count() / PageSize));
        }

    return View(people);
}

Here I populate the Data property with the first 5 people ordered by surname, and calculate the number of pages I require for the amount of data I have. I currently have 12 records so it works out that I need 3 pages.

To show my list of people I have a partial view called “PersonList” which looks like this:

@model AjaxPaging.Helpers.PagedData<AjaxPaging.Models.Person>

<table>
    <thead>
        <tr>
            <th>
                Forename
            </th>
            <th>
                Surname
            </th>
            <th>
                Location
            </th>
        </tr>
    </thead>
    <tbody>
    @foreach (var person in Model.Data)
    {
        <tr>
            <td>
                @person.Forename
            </td>
            <td>
                @person.Surname
            </td>
            <td>
                @person.Country
            </td>
        </tr>
    }
    </tbody>
    <tfoot>
        <tr>
            <td colspan="3">
                @for (int i = 1; i <= Model.NumberOfPages; i++)
                {
                    <a class="page-number" href="javascript:void();">@i</a>
                }
            </td>
        </tr>
    </tfoot>
</table>

It simply loops over the data and outputs a table row for each item, then renders an HTML anchor tag for each of the pages, which currently do nothing. I’ve given each link the class name ‘page-number’ which I’ll use with jQuery in a moment.

So next I need to be able to click one of these pages and have it load that page of data. To do this I’m going to add a new action method that returns the output of the same partial view I’m already using from the Index view. I’ll then call this action method using ajax, and replace the current grid with the result. Sounds too easy? It is…

First I’ve add a new property to my PagedData helper class for the current page. I’ll use this to disable the link in the list of page numbers so it’s clear what page¬† you are currently on:

public class PagedData<T> where T : class
{
    public IEnumerable<T> Data { get; set; }
    public int NumberOfPages { get; set; }
    public int CurrentPage { get; set; }

}

Next I create my new action method which I’ve called PersonList to match the name of my partial view:

public ActionResult PersonList(int page)
{
    var people = new PagedData<Person>();

    using (var ctx = new AjaxPagingContext())
    {
        people.Data = ctx.People.OrderBy(p => p.Surname).Skip(PageSize * (page -1)).Take(PageSize).ToList();
        people.NumberOfPages = Convert.ToInt32(Math.Ceiling((double)ctx.People.Count() / PageSize));
        people.CurrentPage = page;
    }

    return PartialView(people);
}

Here the page parameter is the page I want to display. I’m using it on the Skip extension method to work out which subset of data I require for the given page. I’m also setting the CurrentPage property of the PagedData helper to the page I’m going to display. Ive also set this property in my Index action method to 1 as that’s the action method used when first going to the page.

The only thing left before adding the jQuery is to wrap the partial view in a wrapper which I can use to replace it’s contents after making the ajax call. I do this in my Index view with a DIV tag with the ID “person-list”:

@model AjaxPaging.Helpers.PagedData<AjaxPaging.Models.Person>

@{
    ViewBag.Title = "Home Page";
}

<h2>People</h2>
<p>
    @Html.ActionLink("Add Person", "Add")
</p>

<div id="person-list">
    @Html.Partial("PersonList")
</div>

Now I just need to add the jQuery to call my action method and update the page. I’ve added this to the top of my Index view:

<script type="text/javascript">
    $().ready(function () {
        $(".page-number").live("click", function () {

            var page = parseInt($(this).html());

            $.ajax({
                url: '@Url.Action("PersonList")',
                data: { "page": page },
                success: function (data) {
                    $("#person-list").html(data);
                }
            });
        });
    });
</script>

I’m using the Live function here so that when the page gets refreshed with ajax the click event handler is re-applied to the paging links. First I get the page number from the anchor tag and parse it to an integer. I then make an ajax call to my new PersonList action method, the result of which is the rendered partial view with the page of data. I then replace the content of the “person-list” DIV with that HTML.

And we’re done, super simple ajax server side paging. This could easily be extended to allow the user to set the page size / number of pages on the form, add sorting etc.

Download source

Posted on by Joe in Ajax, ASP.NET, C#, jQuery, MVC

24 Responses to ASP.NET MVC simple server-side ajax paging using jQuery

  1. Saeed Neamati

    Great article. Thank you for sharing. Though Microsoft has officially announced that MVC is not a replacement for Web Froms, I think it will replace it. MVC is much more native to the web development concepts and as much as I’ve worked with it, the most complete pattern ever. Paging in the fucking world of Microsoft controls (in web forms) is just a headache with all that viewstate and control state data.
    Anyway, let’s support CSS3. Read CSS Animations and see an example of it at My heart beats using Google Chrome latest version.

  2. Joe

    Saeed

    Thanks for you comment and shameless plug of your own blog.

    I agree, now that I’m using MVC I never want to see another web form again.

    Cheers
    Joe

  3. nyett

    thank you very much for this great tutorial.. I am a beginner in ASP.NET and found this article really helps me creating pagination (server side data and ajax)
    once again. thanks :)

  4. Bob Willson

    Hi,

    Please can you explain what this is?
    AjaxPagingContext()

    Bob

  5. Joe

    Hi Bob

    It’s my DbContext for Entity Framework Code First. I just called it AjaxPagingContext as my demo project was called AjaxPaging.

    Probably not the best choice of name, it’s got nothing to do with Ajax or Paging, it’s just for EF.

    Cheers
    Joe

  6. Mike

    Hi Bob,

    When I click the page number link, I have javascript syntax error. Looks like something wrong with the $(“.page-number”).live(“click”, function () …

    and I don’t see the paging records occurred on page.

    Please help!
    Mike

  7. Joe

    Mike

    Did you download the example source code?

    I just tried it on FF and IE and it works fine. I can’t really help without seeing what your issue actually is.

    Cheers
    Joe

  8. Mike

    Joe,

    I did download the source code. I didn’t use DbContext for Entity Framework. Instead, I use SqlDataReader to get the data. I don’t think this is the problem. This is all I changed.

    The error is the javascript when I click the page number. In IE, it said syntax error.
    In FF, it has no error, but nothing happens after the number is clicked.

    I can email you if you want to see all my code.

    Here is my class to get the data:

    public class Repository:IDisposable
    {
    public List RepList()
    {
    string sql = “select top 100 * from vw_srchrst”;
    List localList = new List();
    using (SqlConnection conn = new SqlConnection(DbConn.WEBDB))
    {
    using (SqlCommand cmd = new SqlCommand(sql, conn))
    {
    conn.Open();
    using (SqlDataReader reader = cmd.ExecuteReader())
    {
    while (reader.Read())
    {
    Listing qa = new Listing();

    qa.ListingId = Convert.ToInt32(reader["Listing_ID"]);
    qa.Address = Convert.ToString(reader["Address"]);
    qa.Price = Convert.ToInt32(reader["price"]);
    localList.Add(qa);
    }

    }
    }

    }

    return localList;
    }

    void IDisposable.Dispose() { }
    public void Dispose() { }

    }

  9. Joe

    Mike

    Hard to see what your problem is from that code, but with my code I’m passing the page number to my action and only getting 5 records at a time from the database.

    Your code looks like you’re just selecting the first 100 records from your table.

    Is there a reason you don’t want to use Linq 2 SQL or EF as it makes selecting pages of data much easier that writing raw SQL?

    If you upload your solution somewhere and give me the link I can have a look for you.

    Cheers
    Joe

  10. Mike

    Hi Joe,

    Here is the link of the solution. For simplicity, I didn’t load the data from db. I just hard-coded on the repository.

    http://www.sketcheasy.com/super/temp/mvcajaxpagingtest.zip

    Thanks
    Mike

  11. Joe

    Hi Mike

    No JavaScript error in that solution you uploaded. The only thing missing is the Skip on the PersonList action, otherwise every page only loads the first 5 records.

    You need to change:

    listings.Data = list.OrderBy(p => p.Address).Take(PageSize).ToList();

    to:

    listings.Data = list.OrderBy(p => p.Address).Skip(PageSize * (page -1)).Take(PageSize).ToList();

    Then it works fine.

    Cheers
    Joe

  12. pen

    Thanks for the post. What would look like your js file if you had separated the jquery to a separate js file? I tried but didn’t work. It works fine if I left it as it is. But want to move it out. Please any help.

  13. pen

    I tried the Jquery by putting in separate js file and made modification to the $.ajax(alert(“Jump”)) works fine but for the original script it doesn’t. think it has something to do with @url.Action(…. Any help?

  14. Joe

    Pen

    Sorry I though I replied to this but not sure where it went.

    You’re correct @Url.Action is C# using the Razor syntax so it’s not going to work in an external JavaScript file. You can replace this with the URL as a string and it will work.

    Cheers
    Joe

  15. Kenan

    Very nice tutorial. Thanks!

  16. Gourav Rampal

    Well Done Joe,
    I really appreciate your piece of code. Its really nice to have a pagination with so ease. I want point one more thing which you might have skipped, you can implement these Data Extraction separately in Model with interfacing the service, that could be more cleaner approach. Hope you Understand.
    Once Again Thumbs Up for your Nice Article.

    Gourav Rampal
    MPN – INDIA (Microsoft Partner Network )

  17. Joe

    Gourav

    Thanks , but I’m not sure I understand what you mean. It sounds like you’re saying your could make the data call from within the model, which would actually be extremely bad practice when it comes to separation of concerns.

    Regards
    Joe

  18. Vishal Kumar

    Great !! it worked for me. thanks for this nice tutorial.
    It solved paging problem in my project!!

  19. Mathias Van Houtte

    Great article!

    I was looking for paging without the awfull gridview :p.

    Easy example to learn with and awesome ajax support! Very smooth to use!

    Thanks!

  20. Saabir Khan

    Greate Solution

  21. Munir

    thanks sir

  22. miki

    Great not paged article about paging, why ?

  23. Joe

    Hi Miki

    I don’t understand your comment. ‘What does Great not paged article’ mean?

    Joe

  24. Christian

    I also had the syntax error and solved it by replacing the “javascript:void();” with simply “#”. Works like a charm (Internet Explorer).

    How about extending the sample with Ordering?

Add a Comment