Paginated lists made really easy (part 1 of 2 – front-end)
by ricardoz on May.14, 2008, under Articles, JavaScript, Web related
You have to display a list of items in a web application, for each item allowing several operations (ie modification, deletion, etc.). The list can potentially be quite long, so pagination is required.
This scenario is common in backoffice web applications and public web sites, be it for administering information or as search results display, etc.
I’ll describe a simple way to implement a lightweight pagination engine that minimizes load on the server and gives the user the better experience possible. In this first installment I’ll focus on the front-end side, describing how to lay out the HTML, load it using AJAX and implementing the basic operations the user needs to navigate in your paginated list.
The HTML
Say for example you have a car list you need to display, the empty HTML for the list can look like:
1 2 3 4 5 6 7 8 9 10 11 12 | <table id="carList">
<thead>
<tr>
<th><a href="javascript:sort('brand')">Brand</a></th>
<th><a href="javascript:sort('model')">Model</a></th>
<th><a href="javascript:sort('serialNo')">Serial number</a></th>
</tr>
</thead>
<tbody id="carList-items">
</tbody>
</table>
<p id="paging"></p> |
For this example I choose to use a table, since it is and should look like a table ;) If you are implementing for example a search results page with a paragraph look you might want to re-structure the HTML as one paragraph for each list item.
Load the data using AJAX
To populate the list we will use AJAX. The premise is to pull from the server only the list items the user will see at each time.
In the following samples I will use DWR as AJAX framework, to simplify Javascript-to-Java communication, and jQuery to simplify my Javascript code and DOM handling.
First of all we need a function to populate the HTML using a collection of result elements:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | function populateList(map){ var list = map["list"]; var totalSize = map["totalSize"]; var listHTML = ""; for (var i in list){ listHTML += "<tr><td>"; listHTML += list[i]["brand"]; listHTML += "</td><td>"; listHTML += "<td>"; listHTML += list[i]["model"]; listHTML += "</td><td>"; listHTML += "<td>"; listHTML += list[i]["serialNo"]; listHTML += "</td>"; listHTML += "</tr>"; } $("#carList-items").html(listHTML); // Render the paging footer with links to each list page pages = (totalSize / rowsPerPage); if (totalSize % rowsPerPage > 1){ pages++; } pagingHtml = "<strong>Page:</strong> "; for (i=1; i<=pages; i++){ if (currentPage == i){ pagingHtml += "<strong>"+i+"</strong> "; } else { pagingHtml += "<a href='javascript:goToPage("+i+");'>"+i+"</a> "; } } $("#paging").html(pagingHtml); } |
This function doesn’t receives a colletion but rather a Map with two elements:
- The actual collection (”list”) of elements to display on the current page
- The number of total elements in the list (”totalSize”), required to calculate the total number of pages.
Then we need a function to allow the user to move to a certain page:
1 2 3 4 | function goToPage(newPage){ currentPage = newPage; CarsFacade.goToPage(newPage,populateList); } |
As you probably guessed we use a page wide variable, currentPage, to store the page number the user is currently viewing.
Quite simple, eh? We are actually leveraging all the logic to the server, accessed through the CarsFacade class (exposed on JavaScript via DWR).
To populate the list for the first time, we can simply call this function for page 1 once the HTML is done loading:
1 2 3 | $(document).ready({ goToPage(1); }); |
Another nice perk is to allow the user to re-sort the list as he desires, for example we could provide a JavaScript function like this for it:
1 2 3 | function sort(attribute){ CarsFacade.sort(attribute, currentPage ,populateList); } |
Basically we ask the server for the same page we are in, but considering the list sorted by a specific attribute, then use the populateList as callback and voila, done!
Implementing the “go to next page” and “go to previous page” features should be quite simple by just re-using the goToPageUsers function and the total list size. I’ll leave that for you to add :P
In the next installment I’ll go into the server side of this story, reviewing how the CarsFacade should look like and how the actual data should be obtained and handled by our application to keep it simple, nice and fast.
October 6th, 2008 on 4:59 am
Good stuff – stumbled on it as I was looking for something almost exactly like this.
Shouldn’t the solution implement caching ont the server to reduce access time for display-only lists – specially with dynamic sorting feature to be provided?
Waiting for part # 2 – is it out yet ?!
October 10th, 2008 on 5:24 am
@ak: I’ll post part 2 in a few days, it’s been sitting on my desktop waiting for a final touch for more than a few weeks now :P
Regarding caching on the server side, it will always depend on the type of back-end you have. If you delegate paging and sorting to the storage component (ie. database) caching might be actually obtrusive. If on the other hand you manage paging and sorting via Java it’s a very good idea to cache all and ask the database for it just once.
March 25th, 2009 on 12:30 am
I have configured the Pagination in my application but
$(”#carList-items”).html(listHTML); statement is not exexute alert will be dispaly ‘null’, please suggest the solution.
Thanks & Reagards
-Sunil Patil
March 25th, 2009 on 8:05 am
@sunil: you probably don’t have an element with “carList-items” as ID. Review your HTML.