Note: Adding the Controls Dynamically
Another option would be to build the navigation controls completely in jQuery. This means you could easily apply it to any table, and the controls would be added automatically. Such an approach is often favored by plugin authors.
You can style the controls however you see fit—but it’s a good idea to hide the controls container in CSS, then show it with jQuery when the page loads. This is so anyone without JavaScript enabled can avoid seeing the redundant controls.
Our widget skeleton looks like this:
chapter_08/08_pagination/index.html (excerpt)
var TABLE = {};
TABLE.paginate = function(table, pageLength) {
// 1. Set up paging information
// 2. Set up the navigation controls
// 3. Show initial rows
pagination = function (direction) {
reveal = function (current) {
// 5. Reveal the correct rows
};
// 4. Move previous and next
}
};
It looks as if there’s a lot to cover—but be assured, it’s stuff you already know. To start off, we grab the table and rows we want to paginate, and do some calculations to figure out how many pages there’ll be:
chapter_08/08_pagination/script.js (excerpt)
// 1. Set up paging information
var $table = $(table);
var $rows = $table.find('tbody > tr');
var numPages = Math.ceil($rows.length / pageLength) - 1;
var current = 0;
Now we have to configure the navigation controls. This is where our structure is important, as we find the controls by climbing up the DOM from our table selection to the wrapper div, then back down to the navigation section. This approach lets you apply the same code to any tables that have been structured appropriately:
chapter_08/08_pagination/script.js (excerpt)
// 2. Set up the navigation controls
var $nav = $table
.parents('.table-wrapper')
.find('.wrapper-paging ul');
var $back = $nav.find('li:first-child a');
var $next = $nav.find('li:last-child a');
We then set the text in the display boxes for the current page and the total length (adding one, because our counters are zero-based). Next, we attach the event handlers for the Previous/Next buttons. When these buttons are clicked, we call our pagination function with the direction we want to move:
chapter_08/08_pagination/script.js (excerpt)
$nav.find('a.paging-this b').text(current + 1);
$nav.find('a.paging-this span').text(numPages + 1);
$back
.addClass('paging-disabled')
.click(function() {
pagination('<');
});
$next.click(function() {
pagination('>');
});
The last part of the setup is to limit how many rows the user sees to begin with. The easiest way to do this is to hide all the table rows, and show only the rows within the range we’re interested in. But how can we select a range of elements with jQuery? We could use the :lt() and :gt() filters—but when it comes time to show, say, rows 10 to 20, the selectors will get a bit messy. Luckily for us there’s the slice action, which takes a start index and an end index as parameters, and returns only the objects within that range:
chapter_08/08_pagination/script.js (excerpt)
// 3. Show initial rows
$rows
.hide()
.slice(0, pageLength)
.show();
Everything looks in order now: our navigation controls are showing the correct page and total, and the first page of data is displaying correctly. But our paging buttons have no function yet. We’ll add some logic to move the current page, and work out whether we should disable buttons (if we’re at either end of the table):
chapter_08/08_pagination/script.js (excerpt)
// 4. Move previous and next
if (direction == "<") { // previous
if (current > 1) {
reveal(current -= 1);
}
else if (current == 1) {
reveal(current -= 1);
$back.addClass("paging-disabled");
}
} else { // next
if (current < numPages - 1) {
reveal(current += 1);
}
else if (current == numPages - 1) {
reveal(current += 1);
$next.addClass("paging-disabled");
}
}
We update the current variable—but not the table itself. To do so, we create an internal function called reveal:
chapter_08/08_pagination/script.js (excerpt)
// 5. Reveal the correct