Monday, October 25, 2010

Using jQuery's pagination

Try out the demo of this jQuery pagination code:

http://d-scribe.de/webtools/jquery-pagination/demo/demo_options.htm

It works pretty well for static/fixed content, but how about for Ajax-based content? What about situations when you want to add elements to the document so that the total number of entries can be changed?

First, the great part of this plug-in is that you can use the pageSelectCallBack() to do your Ajax query. The demo_ajax.htm that comes with this plug-in shows you the basic approach. The challenge of course comes if you have a situation when you want to add/update existing entries and have the changes reflected in the pagination.

In order to accomplish this last part, several changes had to be made to the jquery.pagination.js code. There are actually several helper functions that get attached to the HTML DIV element, including selectPage(), prevPage(), nextPage().

1) I noticed first that the selectPage() was originally:
containers.each(function () {
        // Attach control functions to the DOM element   
       this.selectPage = function (page_id) { pageSelected(page_id);}

But this line appears to be a bug since the PageSelected() takes in an event object, and sets the current page using the event target and retrieves the page ID from there.
function pageSelected(evt) {
            var links, current_page = $(evt.target).data('page_id');
            containers.data('current_page', current_page);
            links = renderer.getLinks(current_page, pageSelected);
            containers.empty();

The way to fix it would be to invoke the callback function directly, similar to how it's done in other parts of the code:
this.selectPage = function (page_id) { opts.callback(page_id, containers); }

2) The other aspect is that we'll add helper functions that will enable us to update the rendering links (updateLinks()), as well as set and retrieve the total number of entries. Since the 'renderer' vars is a variable local to the scope, this addition was one way to get access to the values without modifying other parts of the existing code:
this.updateLinks = function() {
                var current_page = containers.data('current_page');
                links = renderer.getLinks(current_page, pageSelected);
                containers.empty();
                links.appendTo(containers);
            }
            this.setTotalPages = function(num) {
                renderer.pc.maxentries = num;
            }

            this.getTotalPages = function(num) {
                return renderer.pc.maxentries;
            }

3) Finally, inside our callback function, we invoke the getTotalPages(), setTotalPages(), and updateLinks() after the Ajax response, assuming that the JSON response returns back a 'total_entries' variable that denotes the total # of entries. Note that since jq is a jQuery object and we need to access the HTML DIV element (and not the jQuery object), we have to use j[0] to get access. (This approach of course limits us to have one pagination plug-in per page, but it can be modified to use each() if necessary).

function pageSelectCallback(page_index, jq) {
    var url = "/get_data";

    if (init === true) {
        $.ajax({
            url: url,
            dataType: 'json',
            data: {
                'start_page': page_index
            },
            success: function (response) {
                if (jq[0].getTotalPages() !== response.total_entries) { // Update the total count                                                                                                                                          
                        jq[0].setTotalPages(response.total_entries);
                        jq[0].updateLinks();

So our diff for the jQuery pagination plug-in looks like:

containers.each(function () {
        // Attach control functions to the DOM element
-       this.selectPage = function (page_id) { pageSelected(page_id);}
-       this.prevPage = function () {
-           var current_page = containers.data('current_page');
-           if (current_page > 0) {
-               pageSelected(current_page - 1);
-               return true;
-           }
-           else {
-               return false;
-           }
-       }
-       this.nextPage = function () {
-           var current_page = containers.data('current_page');
-           if(current_page < numPages()-1) {
-               pageSelected(current_page+1);
-               return true;
-           }
-           else {
-               return false;
-           }
-       }
+           this.selectPage = function (page_id) { opts.callback(page_id, containers); }
+           this.prevPage = function () {
+               var current_page = containers.data('current_page');
+               if (current_page > 0) {
+                   pageSelected(current_page - 1);
+                   return true;
+               }
+               else {
+                   return false;
+               }
+           }
+           this.nextPage = function () {
+               var current_page = containers.data('current_page');
+               if(current_page < numPages()-1) {
+                   pageSelected(current_page+1);
+                   return true;
+               }
+               else {
+                   return false;
+               }
+           }
+            this.updateLinks = function() {
+               var current_page = containers.data('current_page');
+               links = renderer.getLinks(current_page, pageSelected);
+               containers.empty();
+               links.appendTo(containers);
+            }
+            this.setTotalPages = function(num) {
+                renderer.pc.maxentries = num;
+            }
+
+            this.getTotalPages = function(num) {
+                return renderer.pc.maxentries;
+            }
        });
        // When all initialisation is done, draw the links
-       links = renderer.getLinks(current_page, pageSelected);
-       containers.empty();
-       links.appendTo(containers);
+        containers.each(function() { this.updateLinks(); });
+
        // call callback function
        opts.callback(current_page, containers);
-
+
 }

2 comments: