Microsoft MVP in ASP.NET/IIS, Senior Software Engineer, Microsoft Certified, MCC (Microsoft Community Contributor), Technology Enthusiast, Speaker, Blogger, Technical Books Reviewer, having several years of experience working in Software Development and Engineering with primary focus on Microsoft technologies. Passionate about contributing to Microsoft Community especially concerning Web Development. Interested in scientific research, BSc., MSc. (candidate) in Computer Sciences, Intelligent Systems. Hajan is a DZone MVB and is not an employee of DZone and has posted 40 posts at DZone. View Full User Profile

Table sorting & pagination with jQuery and Razor in ASP.NET MVC

02.14.2011
| 29725 views |
  • submit to reddit

Introduction

jQuery enjoys living inside pages which are built on top of ASP.NET MVC Framework.

The ASP.NET MVC is a place where things are organized very well and it is quite hard to make them dirty, especially because the pattern enforces you on purity (you can still make it dirty if you want so ;) ).

We all know how easy is to build a HTML table with a header row, footer row and table rows showing some data. With ASP.NET MVC we can do this pretty easy, but, the result will be pure HTML table which only shows data, but does not includes sorting, pagination or some other advanced features that we were used to have in the ASP.NET WebForms GridView. Ok, there is the WebGrid MVC Helper, but what if we want to make something from pure table in our own clean style?

In one of my recent projects, I’ve been using the jQuery tablesorter and tablesorter.pager plugins that go along. You don’t need to know jQuery to make this work… You need to know little CSS to create nice design for your table, but of course you can use mine from the demo… So, what you will see in this blog is how to attach this plugin to your pure html table and a div for pagination and make your table with advanced sorting and pagination features.

 Demo Project Resources

The resources I’m using for this demo project are shown in the following solution explorer window print screen:

  • Content/images – folder that contains all the up/down arrow images, pagination buttons etc. You can freely replace them with your own, but keep the names the same if you don’t want to change anything in the CSS we will built later.
  • Content/Site.css – The main css theme, where we will add the theme for our table too
  • Controllers/HomeController.cs – The controller I’m using for this project
  • Models/Person.cs – For this demo, I’m using Person.cs class
  • Scripts – jquery-1.4.4.min.js, jquery.tablesorter.js, jquery.tablesorter.pager.js – required script to make the magic happens
  • Views/Home/Index.cshtml – Index view (razor view engine)

the other items are not important for the demo.

ASP.NET MVC

1. Model

In this demo I use only one Person class which defines Person entity with several properties. You can use your own model, maybe one which will access data from database or any other resource.

Person.cs

public class Person
{
public string Name { get; set; }
public string Surname { get; set; }
public string Email { get; set; }
public int? Phone { get; set; }
public DateTime? DateAdded { get; set; }
public int? Age { get; set; }

public Person(string name, string surname, string email,
int? phone, DateTime? dateadded, int? age)
{
Name = name;
Surname = surname;
Email = email;
Phone = phone;
DateAdded = dateadded;
Age = age;
}
}

2. View

In our example, we have only one Index.chtml page where Razor View engine is used. Razor view engine is my favorite for ASP.NET MVC because it’s very intuitive, fluid and keeps your code clean.

3. Controller

Since this is simple example with one page, we use one HomeController.cs where we have two methods, one of ActionResult type (Index) and another GetPeople() used to create and return list of people.

HomeController.cs
public class HomeController : Controller
{
//
// GET: /Home/

public ActionResult Index()
{
ViewBag.People = GetPeople();
return View();
}

public List<Person> GetPeople()
{
List<Person> listPeople = new List<Person>();

listPeople.Add(new Person("Hajan", "Selmani", "hajan@hajan.com", 070070070,DateTime.Now, 25));
listPeople.Add(new Person("Straight", "Dean", "email@address.com", 123456789, DateTime.Now.AddDays(-5), 35));
listPeople.Add(new Person("Karsen", "Livia", "karsen@livia.com", 46874651, DateTime.Now.AddDays(-2), 31));
listPeople.Add(new Person("Ringer", "Anne", "anne@ringer.org", null, DateTime.Now, null));
listPeople.Add(new Person("O'Leary", "Michael", "23sssa@asssa.org", 32424344, DateTime.Now, 44));
listPeople.Add(new Person("Gringlesby", "Anne", "email@yahoo.org", null, DateTime.Now.AddDays(-9), 18));
listPeople.Add(new Person("Locksley", "Stearns", "my@email.org", 2135345, DateTime.Now, null));
listPeople.Add(new Person("DeFrance", "Michel", "email@address.com", 235325352, DateTime.Now.AddDays(-18), null));
listPeople.Add(new Person("White", "Johnson", null, null, DateTime.Now.AddDays(-22), 55));
listPeople.Add(new Person("Panteley", "Sylvia", null, 23233223, DateTime.Now.AddDays(-1), 32));
listPeople.Add(new Person("Blotchet-Halls", "Reginald", null, 323243423, DateTime.Now, 26));
listPeople.Add(new Person("Merr", "South", "merr@hotmail.com", 3232442, DateTime.Now.AddDays(-5), 85));
listPeople.Add(new Person("MacFeather", "Stearns", "mcstearns@live.com", null, DateTime.Now, null));

return listPeople;
}
}


TABLE CSS/HTML DESIGN

Now, lets start with the implementation. First of all, lets create the table structure and the main CSS.

1. HTML Structure

@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<title>ASP.NET & jQuery</title>
<!-- referencing styles, scripts and writing custom js scripts will go here -->
</head>
<body>
<div>
<table class="tablesorter">
<thead>
<tr>
<th> value </th>
</tr>
</thead>
<tbody>
<tr>
<td>value</td>
</tr>
</tbody>
<tfoot>
<tr>
<th> value </th>
</tr>
</tfoot>
</table>
<div id="pager">

</div>
</div>
</body>
</html>

So, this is the main structure you need to create for each of your tables where you want to apply the functionality we will create. Of course the scripts are referenced once ;).

As you see, our table has class tablesorter and also we have a div with id pager. In the next steps we will use both these to create the needed functionalities.

The complete Index.cshtml coded to get the data from controller and display in the page is:

<body>
<div>
<table class="tablesorter">
<thead>
<tr>
<th>Name</th>
<th>Surname</th>
<th>Email</th>
<th>Phone</th>
<th>Date Added</th>
</tr>
</thead>
<tbody>
@{
foreach (var p in ViewBag.People)
{
<tr>
<td>@p.Name</td>
<td>@p.Surname</td>
<td>@p.Email</td>
<td>@p.Phone</td>
<td>@p.DateAdded</td>
</tr>
}
}
</tbody>
<tfoot>
<tr>
<th>Name</th>
<th>Surname</th>
<th>Email</th>
<th>Phone</th>
<th>Date Added</th>
</tr>
</tfoot>
</table>
<div id="pager" style="position: none;">
<form>
<img src="@Url.Content("~/Content/images/first.png")" class="first" />
<img src="@Url.Content("~/Content/images/prev.png")" class="prev" />
<input type="text" class="pagedisplay" />
<img src="@Url.Content("~/Content/images/next.png")" class="next" />
<img src="@Url.Content("~/Content/images/last.png")" class="last" />
<select class="pagesize">
<option selected="selected" value="5">5</option>
<option value="10">10</option>
<option value="20">20</option>
<option value="30">30</option>
<option value="40">40</option>
</select>
</form>
</div>
</div>
</body>

So, mainly the structure is the same. I have added @Razor code to create table with data retrieved from the ViewBag.People which has been filled with data in the home controller.

2. CSS Design
The CSS code I’ve created is:

/* DEMO TABLE */
body {
font-size: 75%;
font-family: Verdana, Tahoma, Arial, "Helvetica Neue", Helvetica, Sans-Serif;
color: #232323;
background-color: #fff;
}
table { border-spacing:0; border:1px solid gray;}
table.tablesorter thead tr .header {
background-image: url(images/bg.png);
background-repeat: no-repeat;
background-position: center right;
cursor: pointer;
}
table.tablesorter tbody td {
color: #3D3D3D;
padding: 4px;
background-color: #FFF;
vertical-align: top;
}
table.tablesorter tbody tr.odd td {
background-color:#F0F0F6;
}
table.tablesorter thead tr .headerSortUp {
background-image: url(images/asc.png);
}
table.tablesorter thead tr .headerSortDown {
background-image: url(images/desc.png);
}
table th { width:150px;
border:1px outset gray;
background-color:#3C78B5;
color:White;
cursor:pointer;
}
table thead th:hover { background-color:Yellow; color:Black;}
table td { width:150px; border:1px solid gray;}


PAGINATION AND SORTING

Now, when everything is ready and we have the data, lets make pagination and sorting functionalities
1. jQuery Scripts referencing

<link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
<script src="@Url.Content("~/Scripts/jquery-1.4.4.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.tablesorter.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.tablesorter.pager.js")" type="text/javascript"></script>

2. jQuery Sorting and Pagination script

<script type="text/javascript">
$(function () {
$("table.tablesorter").tablesorter({ widthFixed: true, sortList: [[0, 0]] })
.tablesorterPager({ container: $("#pager"), size: $(".pagesize option:selected").val() });
});
</script>

So, with only two lines of code, I’m using both tablesorter and tablesorterPager plugins, giving some options to both these.
Options added:

  • tablesorter - widthFixed: true – gives fixed width of the columns
  • tablesorter - sortList[[0,0]] – An array of instructions for per-column sorting and direction in the format: [[columnIndex, sortDirection], ... ] where columnIndex is a zero-based index for your columns left-to-right and sortDirection is 0 for Ascending and 1 for Descending. A valid argument that sorts ascending first by column 1 and then column 2 looks like: [[0,0],[1,0]] (source: http://tablesorter.com/docs/)
  • tablesorterPager – container: $(“#pager”) – tells the pager container, the div with id pager in our case.
  • tablesorterPager – size: the default size of each page, where I get the default value selected, so if you put selected to any other of the options in your select list, you will have this number of rows as default per page for the table too.


END RESULTS

1. Table once the page is loaded (default results per page is 5 and is automatically sorted by 1st column as sortList is specified)

2. Sorted by Phone Descending

3. Changed pagination to 10 items per page


4. Sorted by Phone and Name (use SHIFT to sort on multiple columns)

5. Sorted by Date Added

6. Page 3, 5 items per page

ADDITIONAL ENHANCEMENTS

We can do additional enhancements to the table. We can make search for each column. I will cover this in one of my next blogs. Stay tuned.


DEMO PROJECT

You can download demo project source code from HERE.

CONCLUSION

Once you finish with the demo, run your page and open the source code. You will be amazed of the purity of your code.

Working with pagination in client side can be very useful. One of the benefits is performance, but if you have thousands of rows in your tables, you will get opposite result when talking about performance. Hence, sometimes it is nice idea to make pagination on back-end. So, the compromise between both approaches would be best to combine both of them. I use at most up to 500 rows on client-side and once the user reach the last page, we can trigger ajax postback which can get the next 500 rows using server-side pagination of the same data. I would like to recommend the following blog post http://weblogs.asp.net/gunnarpeipman/archive/2010/09/14/returning-paged-results-from-repositories-using-pagedresult-lt-t-gt.aspx, which will help you understand how to return page results from repository.

I hope this was helpful post for you. Wait for my next posts ;).

Please do let me know your feedback.

Best Regards,
Hajan













































Published at DZone with permission of Hajan Selmani, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Jacek Furmankiewicz replied on Mon, 2011/02/14 - 1:09pm

And this is relevant to Java how? Why is this showing up on the front page of JavaLobby?

Mark Unknown replied on Mon, 2011/02/14 - 1:17pm in response to: Jacek Furmankiewicz

So you can see how fantastic ASP.NET MVC is so you will dump silly Java.

Really, I am sure some wires got crossed and something from the ASP.NET zone got posted here. It is Monday, after all.

Jacek Furmankiewicz replied on Mon, 2011/02/14 - 1:47pm in response to: Mark Unknown

Ah yes, the good old MS superiority complex...had a chance to experience it well during my 5 years in .Net...before I switched to Linux and Java. Best decision ever.

Hajan Selmani replied on Mon, 2011/02/14 - 2:06pm

@Jacek, it's more personal than objective judgement to say some platform is better than other. If you are productive with the one you are working with... stay with it, otherwise you need to look what's happening in the neighbourhood ;). ASP.NET MVC promises a lot and I expect it to become one of the most used web development platforms in the years to come.

Thanks for the comments.

Jacek Furmankiewicz replied on Mon, 2011/02/14 - 2:40pm in response to: Hajan Selmani

Now that is a polite comment I can agree with :-)
And yes, I do check out what's in the other neighbourhoods all the time (Python, Ruby, etc.). I was actually valiantly trying to get going with Boo (nice little .Net language) in MonoDevelop in Linux just a few weeks ago.

Michal Xorty replied on Tue, 2011/02/15 - 4:08am

Why do you post this stuff at Java site? I don't care.

Gernot Kogler replied on Tue, 2011/02/15 - 11:57am

Sending 500 table rows to the client and do the pagination and sorting there seems not like a great idea to me. If you change the sorting you'll have to reload the data anyway if there are more than 500 records in the database. And what should the user do with 500 records in a table? What is the use case? I think there are much better ways to find and present information in a modern web application. Paginated tables look so 1990.

Mark Unknown replied on Tue, 2011/02/15 - 2:46pm in response to: Jacek Furmankiewicz

@Jacek, As always, humor goes over like a lead balloon... I highly doubt the poster was trying to "sell" ASP.NET MVC to us. I was trying to make light of the matter.

Mark Unknown replied on Tue, 2011/02/15 - 2:53pm in response to: Hajan Selmani

I am sure ASP.NET MVC is interesting. For the things i do, WebGUI is a better fit, if i must do .NET. And sometimes plain ol ASP.NET will be good enough, as painful as it is for me to say it. But for seeing the other neighborhood? The Java platform/community has plenty of MVC frameworks. Plus plenty of other things to look at and learn with out seeing what Microsoft is [finally] doing. Now, if I was building an MVC framework I might be tempted to take a peek. ;) But thanks for sharing! (if that what you really intended to do)

Hajan Selmani replied on Tue, 2011/02/15 - 7:30pm

@Mark, the main choice is wheter you go with .NET, Java or any-other as a platform. MVC is the pattern used in the ASP.NE MVC Framework. You can build app using MVC pattern even when using ASP.NET Webforms ;). However, there are number of advantages of using ASP.NET MVC comparing to ASP.NET WebForms, but still as I said in my previous comment, if things work fine for you building with any of these or any third, then stick with it.

Thanks for your comments.

 @Jacek, thanks once again :)

 @Gernot, if user changes the order, we can still catch the 500 records (as said in the example) that need to be displayed and paginated. Your logic makes sense. Still, this is a method I proposed only to reduce the ajax calls to the server, but sometimes other methods (depends of the scenario) might be used. I didn't say this is the ultimatively perfect.

Mark Unknown replied on Tue, 2011/02/15 - 8:30pm in response to: Hajan Selmani

@Hajan, Yeah. That is what i was saying about the Neighborhoods. If i choose Java (for instance), no point in looking unless i am going to change neighborhoods.
Yes i know MVC is the pattern for ASP.NET MVC (duh?)
I know there are advantages for using ASP.NET MVC over just Webforms. But there are disadvantages too. That is my point. (FYI - I have use MVC web frameworks in the past). Well, i would rather compare something like WebGUI versus ASP.NET MVC. ASP.NET Winforms tries to be middle of the road and ends up causing more problems than it solves. I would not use it for more than anything simple like a single page.

It is not just "what works for you", it is "what are you trying to build?". Like I said, glad to see the Microsoft is finally figuring out that one web framework does not cut it. Or are they? They really need to bring WebGUI into the fold. I think they think Silverlight will do the same. I don't think it does. Sometimes you need the Form development without the runtime.

Carla Brian replied on Sat, 2012/04/28 - 6:04am

Thanks for sharing this one. I think this is efficient. I will look for tutorials on this. - Incredible Discoveries

Raghav Goud replied on Sat, 2013/03/02 - 2:00am

when change pagination to 2nd i.e 11 to 20 then i have change the status of one column in that  case how can i remain in same pagination  

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.