Sep 16

Simple HtmlHelper Extension for Paging in ASP.Net MVC

This post discusses modifications to the (I)PagedList and extending HtmlHelper for simple paging.

I am on my third implementation of paging for blog posts, and finally am happy~ish with the implementation :). I first had an inline for loop (not very reusable), then I moved the code to a partial view (it was ok, but didn't feel quite right), and now I have finally settled on extending the HtmlHelper object.

I started off with ScottGu's PagedList<T> that I found on Rob Conery's blog. I made some small modifications based on my needs and preferences: download here. I basically ended up with IPagedList and IPagedList<T> interfaces and the PagedList<T> implementation itself. I needed the IPagedList<T> so that I could have strongly typed objects in the View, but the pager itself doesn't need to know the type. So, it gets the plain IPagedList.

Here is my Paging extension method:

public static string Paging(this HtmlHelper html, IPagedList pagedList,
     string url, string pagePlaceHolder) {

     StringBuilder sb = new StringBuilder();

     // only show paging if we have more items than the page size
     if (pagedList.ItemCount > pagedList.PageSize) {

        sb.Append("<ul class=\"paging\">");

        if (pagedList.IsPreviousPage) { // previous link
           sb.Append("<li class=\"prev\"><a href=\"");
           sb.Append(url.Replace(pagePlaceHolder, pagedList.PageIndex.ToString()));
           sb.Append("\" title=\"Go to Previous Page\">prev</a></li>");
        }

        for (int i = 0; i < pagedList.PageCount; i++) {
           sb.Append("<li>");
           if (i == pagedList.PageIndex) {
              sb.Append("<span>").Append( (i+1).ToString() ).Append("</span>");
           } else {
              sb.Append("<a href=\"");
              sb.Append(url.Replace(pagePlaceHolder, (i+1).ToString()));
              sb.Append("\" title=\"Go to Page ").Append( (i+1).ToString() );
              sb.Append("\">").Append( (i+1).ToString() ).Append("</a>");
           }
           sb.Append("</li>");
        }

        if (pagedList.IsNextPage) { // next link
           sb.Append("<li class=\"next\"><a href=\"");
           sb.Append(url.Replace(pagePlaceHolder, (pagedList.PageIndex + 2).ToString()));
           sb.Append("\" title=\"Go to Next Page\">next</a></li>");
        }

        sb.Append("</ul>");
     }

     return sb.ToString();
  }

This is how you would invoke the method from a view:

<%= Html.Paging(ViewData.Model, Url.Action("Index","Blog", new { page = "__PAGENUM__" }), "__PAGENUM__") %>

As you can see, the method takes in an IPagedList, a URL with a placeholder for the page number, and the placeholder value itself. This way the pager can easily create links to the pages by simple replacing the placeholder with the page number desired.

After implementing this, I googled around to see if I had reinvented the wheel. I did find that Martijn Boland implemented a pager thats a bit more sophisticated. But does a pager class/method really need to know how to use the RouteTable to create URLs? I would prefer that it not. In fact, my code can be used in web forms and other non asp.net mvc projects.

Update (9/18/2008): Two more MVC paging related blog posts:

Tags:

Powered by my hackings on Django-Mingus a Django project, PostgreSQL, memcached, nginx, Apache + mod_wsgi, Ubuntu, Rackspace Cloud,...

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

html5 | top