JQuery DataTable Plugin Pagination

by

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):

Screen shot 2011-11-21 at 8.01.59 PM
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:

  1. Pagination plug-in: html structure and behavior
  2. Page information plug-in: to obtain information about the current page index
  3. Code to initialize the pagination html components
  1. 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"); } } } }; 
  2. 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 ) }; } 
  3. 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

  1. william on said:

    ok, first thanks for the lesson

    now, I had to make some enhancements for my code

    this might be usefull for someone

    when there is no data, your code printed : page 1 of 0

    my code prints: page 1 of 1

    “fnDrawCallback”: function() {
    var length = this.fnGetData().length;
    /*
    if (length 0 ? this.fnPagingInfo().iTotalPages : 1);
    },

    and your div is hidden:

    if (length <= this.fnPagingInfo().iLength) {
    $(this).parent().children(".dataTables_paginate").hide();
    }

    set to show:

    $(this).parent().children(".dataTables_paginate").show();

    or comment the hide command

    thx

  2. Fae on said:

    I tried this in jsbin but the previous and next buttons are not showing. any idea why?

    • Giuseppe Macri
      Giuseppe Macri on said:

      The example i posted on github repo doesn’t replicate the image shown in the above post.
      The example provides javascript code, css and html structure but with different images.
      once you have cloned the git repo just open zero_config.html. The html should show the new navigation plugin in action.

  3. Giuseppe Macri
    Giuseppe Macri on said:

    Hi Brandon,
    thank you for your comment.
    I updated the github repo. Please check it out.
    I look forward for your feedback

    Giuseppe

  4. brandon on said:

    this is cool and I would use it but your github is empty – you should commit it again ;-D and update the link in this article take one to it

    • Giuseppe Macri
      Giuseppe Macri on said:

      Hi Brandon,
      thank you for your comment.
      I updated the github repo. Please check it out.
      I look forward for your feedback

      Giuseppe

Leave a Reply to Fae Cancel reply

Your email address will not be published. Required fields are marked