JQuery DataTable Plugin Pagination
One of the most common tasks when displaying data through an HTML table is to allow the user to manipulate data within the table. Displaying data on a grid can involve many different operations (retrieving, sorting, live editing, search). Using AJAX to dynamically fill the table requires even more work since the application (in this case, javascript code) has to convert JSON/XML/TEXT data to an HTML element. Each of these tasks can involve more or less time in order to be completed, and of course, tested.
Rather than starting the implementation from scratch I decided to look around for a jQuery plugin able to perform all the necessary operations on a grid (retrieving, sorting, searching, exporting).
After trying out different plugins I ended up choosing the DataTable plugin.
From the first look at the examples on the official website (http://datatables.net/) the plugin looked extremely easy to use and flexible to customize (data sources, data type detection). Some of the key features are listed below:
- Variable length pagination
- On-the-fly filtering
- Display data from almost any data source: DOM, Javascript array, Ajax file and server-side processing (PHP, C#, Perl, Ruby, AIR, Gears etc)
- Dynamic creation of tables
- Ajax auto loading of data
- Custom DOM positioning
- Single column filtering
- Sorting column(s) highlighting
- Extensive plug-in support
- Sorting, type detection, API functions, pagination and filtering.
Most of the features of the plugin are enabled by default so the developer can focus on the real problems (business logic). Here is a “zero configuration” example:
HTML Code:
(create your own table within your html page something like this):
<table cellpadding="0" cellspacing="0" border="0" class="display" id="example"> <thead> <tr> <th>Rendering engine</th> <th>Browser</th> <th>Platform(s)</th> <th>Engine version</th> <th>CSS grade</th> </tr> </thead> <tbody> <tr class="odd gradeX"> <td>Trident</td> <td>Internet Explorer 4.0</td> <td>Win 95+</td> <td class="center"> 4</td> <td class="center">X</td> </tr> <tr class="even gradeC"> <td>Trident</td> <td>Internet Explorer 5.0</td> <td>Win 95+</td> <td class="center">5</td> <td class="center">C</td> </tr> … </tbody> </table>
Remember to include the javascript plugin file:
<script type="text/javascript" language="javascript" src="js/jquery.dataTable.mins.js"></script>
and finally call the datatable function:
<script type="text/javascript" charset="utf-8"> $(document).ready(function() { $('#example').dataTable(); }); </script>
You can download this example from github (https://github.com/GrioSF/datatablepaginationplugin).
Now that you have an idea (of course you can take a look at the documentation), we can now move on to the real topic of this post, implementing custom pagination controls for the DataTable plugin.
Of course, the plug-in lets the developer to build his/her own style and logic for pagination. Customizing the pagination was the hardest part among all the possible plug-in’s operations I had to perform.
I created the following pagination style (the code on github will provide css code to reproduce the structure but not the exact style):
The component contains 3 different parts: a previous button, an information field and a next button.
I decided to modify one of the examples provided on the website in order to create my own plug-in.
The code is divided into three parts:
- Pagination plug-in: html structure and behavior
- Page information plug-in: to obtain information about the current page index
- Code to initialize the pagination html components
- Pagination plug-in: This is the core of the new pagination controls. This code will create HTML elements and logic to handle the previous and next buttons:
/** * Datatable plugin pagination style */ $.fn.dataTableExt.oPagination.extStyleLF = { /* * Function: oPagination.extStyle.fnInit * Purpose: Initalise dom elements required for pagination with a list of the pages * Returns: - * Inputs: object:oSettings - dataTables settings object * node:nPaging - the DIV which contains this pagination control * function:fnCallbackDraw - draw function which must be called on update */ "fnInit": function (oSettings, nPaging, fnCallbackDraw) { /* * code to create pagination buttons */ nPrevious = $('<span />', { 'class': 'paginate_button previous' }); nNext = $('<span />', { 'class': 'paginate_button next' }); /* * code to create pagination information field */ var navigationLabel = 'Page <span class="pageIndex">#</span> of <span class="totalPages">TOTAL</span>'; navLabel = $('<div />', { html: navigationLabel, 'class': 'navigationLabel'}); $(nPaging) .append(nPrevious) .append(navLabel) .append(nNext); nPrevious.click(function () { oSettings.oApi._fnPageChange(oSettings, "previous"); fnCallbackDraw(oSettings); }).bind('selectstart', function () { return false; }); nNext.click(function () { oSettings.oApi._fnPageChange(oSettings, "next"); fnCallbackDraw(oSettings); }).bind('selectstart', function () { return false; }); }, /* * Function: oPagination.extStyle.fnUpdate * Purpose: Update the list of page buttons shows * Returns: - * Inputs: object:oSettings - dataTables settings object * function:fnCallbackDraw - draw function which must be called on update */ "fnUpdate": function (oSettings, fnCallbackDraw) { if (!oSettings.aanFeatures.p) { return; } /* Loop over each instance of the pager */ var an = oSettings.aanFeatures.p; for (var i = 0, iLen = an.length; i < iLen; i++) { //var buttons = an[i].getElementsByTagName('span'); var buttons = $(an[i]).find('span.paginate_button'); if (oSettings._iDisplayStart === 0) { buttons.eq(0).attr("class", "paginate_disabled_previous paginate_button"); } else { buttons.eq(0).attr("class", "paginate_enabled_previous paginate_button"); } if (oSettings.fnDisplayEnd() == oSettings.fnRecordsDisplay()) { buttons.eq(1).attr("class", "paginate_disabled_next paginate_button"); } else { buttons.eq(1).attr("class", "paginate_enabled_next paginate_button"); } } } };
- Page information plugin (provided by the official website): this code is an helper for the plugin so the application can easily retrieve information about pagination (current page, total number of pages):
/** * Datatable plugin page information */ $.fn.dataTableExt.oApi.fnPagingInfo = function ( oSettings ) { return { "iStart": oSettings._iDisplayStart, "iEnd": oSettings.fnDisplayEnd(), "iLength": oSettings._iDisplayLength, "iTotal": oSettings.fnRecordsTotal(), "iFilteredTotal": oSettings.fnRecordsDisplay(), "iPage": Math.ceil( (oSettings._iDisplayStart + oSettings._iDisplayLength) / oSettings._iDisplayLength ), "iTotalPages": Math.ceil( oSettings.fnRecordsDisplay() / oSettings._iDisplayLength ) }; }
- Code to initialize html components:
$(document).ready(function() { var oTable = $('#example').dataTable({ "sPaginationType": "extStyleLF", "bAutoWidth": false, "fnDrawCallback": function () { var length = this.fnGetData().length; if (length <= this.fnPagingInfo().iLength) { $(this).parent().children(".dataTables_paginate").hide(); } $(this).parent().find(".dataTables_paginate .navigationLabel .pageIndex") .text(" " + this.fnPagingInfo().iPage + " "); $(this).parent().find(".dataTables_paginate .navigationLabel .totalPages") .text(this.fnPagingInfo().iTotalPages); }, "sDom" : '<"clear">ilprtp' }); });
As you can see, a lot of code is needed to customize the pagination controls (compared to other customizations) but the official website and the forum contains a lot of useful information. In addition, the documentation offers good examples to use as a starting point. I highly recommend the JQuery DataTable plug-in for your tabulation needs.
Giuseppe
6 Comments