I recently worked on a project where there may be several listings modules on a page; I wrote a jQuery plugin to manage the pagination for these and would really appreciate any feedback or thoughts.
It currently manages the loading of content via AJAX on a pagination link click, with dedicated parameters for filtering and sorting the output. Basically speaking, it'll look for two UL elements, identified by classes, inside your target container; one for the links list, and one for the content list.
It's my first real effort at a plugin, and there are likely to be some omissions. I'm aware that there's stuff hardcoded that could easily be transferred to the defaults (like the "Prev" / "Next" text).
One thing I really don't like about it is that it is a bit AJAX-happy. Each pagination module on a page requires two server-side pages: one to return a count of the total number of items to paginate (I'd assume that this was running off a database), and one to return the actual listing content for a pagination 'page'. I can't see how you can get around it; you have to get the total number of items in order to know how many pagination links to create. But any observations would be welcomed.
Anyway here it is. If you think it might be useful in whatever form, feel free to use it. If you do tweak it, it would be nice if you could put a comment up here so we can see what you did
Code:
(function($) {
$.fn.paginate = function(params) {
// default / initial settings
var defaults = {
itemsPerPage : 2, // number of items to show per page
currentPage : 1, // current page number
itemCount : 0, // total number of items to paginate
linksToShow : 5, // maximum amount of numbered links to show
contentURLPrefix : "/php/ajax/_ajaxlist_", // prefix for filename to load listings from
contentURLSuffix : ".php", // suffix for filename to load listings from
countURLPrefix : "/php/ajax/_ajaxcount_", // prefix for filename to load item count from
countURLSuffix : ".php", // suffix for filename to load item count from
loadInitialContent: true, // if true, go and fetch the first page of content (otherwise assume that the containing page has already done so)
onPagedLoad: null, // callback function fired when a page of content is loaded
queryfilters: {}, // key:value pairs of filter parameters to pass to content-fetching / count pages
querysort: "", // comma-separated list of sort columns to pass to content-fetching pages
ajaxvars: {}, // key:value pairs of miscellaneous vars to pass to content-fetching / count pages.
// Treated the same way as queryfilters except they're not written to pagination links
contentContainer: ".modulecontentlist", // the classname of the container that the content will be loaded in to
linksContainer: ".pagelinks" // the classname of the container that the numbered page links will be loaded into
};
var options = $.extend(defaults, params);
return this.each(function() {
var $this = $(this);
// update the itemCount via AJAX if it's not been passed in.
if (options.itemCount == 0){
var countSourceURL = options.countURLPrefix + $this.attr("id") + options.countURLSuffix;
$.get(countSourceURL, options.queryfilters, function(ct){
options.itemCount = parseInt(ct);
if (options.loadInitialContent){
getInitialContent($this);
}else{
drawPaginationLinks($this);
if ($.isFunction(options.onPagedLoad)) {
options.onPagedLoad($this);
}
}
});
}else{
if (options.loadInitialContent){
getInitialContent($this);
}else{
drawPaginationLinks($this);
if ($.isFunction(options.onPagedLoad)) {
options.onPagedLoad($this);
}
}
}
});
function drawPaginationLinks($this){
// draw a list of pagination links
if (options.itemCount > options.itemsPerPage){
var maxPageNumber = Math.ceil(options.itemCount / options.itemsPerPage);
var linkCount = options.linksToShow - 1 // make linkCount 0-based, not 1-based.
// normally start numbering at one below the current page, unless we're at page 1.
var startPageNumber = (options.currentPage > 1) ? options.currentPage - 1 : options.currentPage;
// keep listing page number links until we get to linkCount, unless we hit maxPageNumber first.
var endPageNumber = startPageNumber + linkCount;
endPageNumber = (endPageNumber > maxPageNumber) ? maxPageNumber : endPageNumber;
// if we're close enough to the end that we're not listing enough pages, and we're far enough away from the beginning, begin numbering earlier.
if (((endPageNumber - startPageNumber) < linkCount) && (startPageNumber > 1)){
startPageNumber = (endPageNumber > linkCount) ? endPageNumber - linkCount : 1;
}
// create filter list for adding to numbered link hrefs
var filterlist = "";
$.each(options.queryfilters, function(key, val){
if (filterlist==""){
filterlist = key + "=" + val;
}else{
filterlist += "&" + key + "=" + val;
}
});
// now create list of numbered links
var sNumberingHTML = '';
// add "Prev" link if appropriate
if (options.currentPage > 1){
sNumberingHTML += '<li><a href="#'+filterlist+'">Prev</a></li>';
}
for (var i = startPageNumber; i <= endPageNumber; i++){
if (options.currentPage == i){
sNumberingHTML += '<li class="current">'+ i +'</li>';
}else{
sNumberingHTML += '<li><a href="#'+filterlist+'">'+ i +'</a></li>';
}
}
// add "Next" link if appropriate
if (options.currentPage < maxPageNumber){
sNumberingHTML += '<li><a href="#'+filterlist+'">Next</a></li>';
}
// add numbered links to container UL
$this.find(options.linksContainer).html(sNumberingHTML);
// add event handlers to newly-added numbering links
$this.find('.' + options.linksContainer + ' li a').click(function(){
getPaginationContent(this,$this);
return false;
});
}else{ //(options.itemCount <= options.itemsPerPage) - don't show pagelinks
$this.find(options.linksContainer).html("");
}
}
function getInitialContent($this){
// get the content for the first page and draw the pagination links.
var contentSourceURL = options.contentURLPrefix + $this.attr("id") + options.contentURLSuffix;
var paginationParams = {pageNumber: options.currentPage, itemsPerPage: options.itemsPerPage, sortby: options.querysort};
var allParams = $.extend(paginationParams, options.queryfilters, options.ajaxvars);
$($this).find(options.contentContainer).load(contentSourceURL, allParams, function(){
drawPaginationLinks($this);
if ($.isFunction(options.onPagedLoad)) {
options.onPagedLoad($this);
}
});
}
function getPaginationContent(pageListLink,$this){
// get the content for the required page, draw the pagination links, and increment the current page count.
var contentSourceURL = options.contentURLPrefix + $this.attr("id") + options.contentURLSuffix;
var pageNumberToGet = $(pageListLink).text();
if (!isNaN(pageNumberToGet)){
pageNumberToGet = parseInt(pageNumberToGet);
}else if (pageNumberToGet == "Next"){
pageNumberToGet = options.currentPage + 1;
}else if (pageNumberToGet == "Prev"){
pageNumberToGet = options.currentPage - 1;
}
var paginationParams = {pageNumber: pageNumberToGet, itemsPerPage: options.itemsPerPage, sortby: options.querysort};
var allParams = $.extend(paginationParams, options.queryfilters, options.ajaxvars);
$($this).find(options.contentContainer).load(contentSourceURL, allParams, function(){
options.currentPage = pageNumberToGet;
drawPaginationLinks($this);
if ($.isFunction(options.onPagedLoad)) {
options.onPagedLoad($this);
}
});
}
};
})(jQuery);
Usage:
Code:
<div id="listItems">
<ul class="pagelinks"></ul>
<ul class="modulecontentlist"></ul>
</div>
Code:
$(document).ready(function(){
$('#listItems').paginate({
itemsPerPage: 24,
queryfilters:{
myParam1:myVal1,
myParam2:myVal2,
}
});
});