Pagination is an essential, and not so easy to implement user interface device that allows the developer to break long lists of items, or one very long item into sub-pages. I love the challenge that pagination brings (who doesn’t really) when developing efficient and reusable server-side code, but this article isn’t about that. Sometimes I need things done quickly, easily, and preferably with as little compromise as possible, and that’s what client-side pagination is all about.
First a shout out to some of the gurus out there, men I admire and whose server-side pagination techniques can only be described as “bloody marvelous”. If you find the need to paginate, and you want to use Apex to do it, check out these articles,
Richard Van Hook’s article on pagination using his excellent Apex library
Jeff Douglas’ article on pagination using StandardSetController
Joel Dietz’s article on pagination with Chatter Bubbles
I’ve used these articles to build server-side Paginators, but recently realised there’s another approach using jQuery plugins, one that offers the following:
Pros
- VERY quick to implement.
- Will work with PageBlockTables, DataTables, Repeats.
- Will work with lists of any type, no matter how complex.
- Will work with lists of mixed types.
- Has nearly zero latency between paginated-pages.
- Seriously, is VERY quick to implement.
Cons
- We’re restricted by the number of items that can be output by PageBlockTables, DataTables, Repeats.
- If your DOM is large, the page will load a touch more slowly.
The technology I’m using to create this pagination is a jQuery plugin I’ve created and cheesely called Pajinate. I’ve written an article on how to implement the plugin for general HTML development, but this article will demo porting the plugin so that it works with VisualForce pages. Enough yapping, let’s write some code.
I’m going to demonstrate two types of implementations, one for DataTables, and the other for Repeats. For the sake of completeness the class that serves as the page controller:
[code language=”java”]
public with sharing class PajinateController {
public List<account> accounts{get;set;}
public PajinateController(){
accounts = [SELECT id, name, rating, annualRevenue, industry FROM Account LIMIT 1000];
}
}
[/code]
DataTables
This is the more difficult implementation, but that doesn’t mean it’s difficult. Unfortunately Salesforce uses a strange method (I’d go so far as to say it’s bad) of automatically generating Ids for VisualForce pages, and this makes our life a smidgen more difficult.
If you peruse the code below, you’ll notice the weird way I’m including JavaScript in the middle of the page, and this is my preferred method for robustly referring to VisualForce elements in JavaScript. Secondly, on line 5 you’ll see that I’m appending a ‘:tb’ to the end of the Id we’ve assigned to the table; this is because we have no way of getting to the TBODY element that is the direct parent of the TR elements we want to page through.
[code language=”xml”]
<apex:pageblock title="Client-Side Paginated DataTable">
<apex:pageblocksection title="Pagination Easy as 1-2-3" columns="1" id="pbs">
<div class="page_navigation"></div>
<script>
/* Feel free to use your favourite method of getting VF component Ids */
var accountTableId = ‘{!$Component.accountTable}’;
var accountTableBodyId = accountTableId + ‘:tb’;
var pbsId = ‘{!$Component.pbs}’;
</script>
<apex:datatable value="{!accounts}" var="account" id="accountTable" rows="1000">
<apex:column>
<apex:facet name="header">Name</apex:facet>
<apex:outputfield value="{!account.name}"></apex:outputfield>
</apex:column>
<apex:column>
<apex:facet name="header">Rating</apex:facet>
<apex:outputfield value="{!account.rating}"></apex:outputfield>
</apex:column>
<apex:column>
<apex:facet name="header">Annual Revenue</apex:facet>
<apex:outputfield value="{!account.annualRevenue}"></apex:outputfield>
</apex:column>
</apex:datatable>
<div class="page_navigation"></div>
</apex:pageblocksection>
</apex:pageblock>
[/code]
That’s the part of the page we need to know about, next we need to know how to attach Pajinate to the table,
[code language=”javascript”]
$.noConflict();
jQuery(document).ready(function($){
$(esc(pbsId)).pajinate({
item_container_id : esc(accountTableBodyId),
items_per_page : 40
});
});
function esc(myid) {
return ‘#’ + myid.replace(/(:|\.)/g,’\\\\$1′);
}
[/code]
And that’s it, done! I don’t like the little hack along the way, but it won’t keep me up at night. Right, what’s next?
Repeats
I love Repeats and they’re my favoured method of building pages using iteration (Maybe I just really don’t like tables, they’re so 2001). Attaching Pajinate to Repeats is very easy, first we build the repeat structure:
[code language=”xml”]
<apex:outputpanel layout="block" styleclass="demo2">
<div class="page_navigation"></div>
<apex:outputtext value="Client-Side Paginated Repeat" styleclass="title block"></apex:outputtext>
<apex:outputpanel layout="block" styleclass="content">
<apex:repeat value="{!accounts}" var="account" rows="50">
<apex:outputpanel layout="block" styleclass="panel">
<apex:outputtext value="{!account.name}" styleclass="head block"></apex:outputtext>
<apex:outputpanel layout="block" styleclass="body">
<apex:outputtext value="{!account.rating}" styleclass="item"></apex:outputtext>
<apex:outputtext value="{!account.annualRevenue}" styleclass="item"></apex:outputtext>
<apex:outputtext value="{!account.industry}" styleclass="item"></apex:outputtext>
</apex:outputpanel>
</apex:outputpanel>
</apex:repeat>
</apex:outputpanel>
</apex:outputpanel>
[/code]
And then, in a fashion very similar to what we did previously, we use some JavaScript to attach the plugin to the required elements:
[code language=”javascript”]
$.noConflict();
jQuery(document).ready(function($){
$(‘.demo2’).pajinate();
});
[/code]
And once again, we’re done.
Give the demos a whirl. I’m sure once you’ve used them you’ll realise that client-side pagination isn’t a second-class citizen. Note that the plugin is also configureable and the options can found on the release page. I’ll also be updating the plugin with new features and bug-fixes from time to time, so check back every now again for the latest code and documentation. For those who are interested, the full code posting can be found here.
Cheesy delicious! A bit confused by the “mce”s hanging around tho.
That’ll be WordPress playing havok with my markup grrrr..
Cheesy delicious! A bit confused by the “mce”s hanging around tho.
That’ll be WordPress playing havok with my markup grrrr..
Cheesy delicious! A bit confused by the “mce”s hanging around tho.
That’ll be WordPress playing havok with my markup grrrr..
Cheesy delicious! A bit confused by the “mce”s hanging around tho.
That’ll be WordPress playing havok with my markup grrrr..
Really $#@! cool! I’m going to add this to our internal AppDEV CoE newsletter.
Thanks bud. I feel like I’m showing client-side a little too much love these days, time to get back to my server-side roots 😉
Looks great Wes.
It seems that the code samples in this tutorial are incomplete. I don’t see the JavaScript in the middle of the Visualforce page on the datatable example, and the ids referenced in your jQuery code don’t match up with the components. I’m guessing that the JavaScript that defines “accountTableBodyId” and “pbsId” is missing from the VF page code?
Rob, I had left that part out intentionally as I was worried that since component Ids in JavaScript are tricky that code might draw the focus away from the jQuery plug-in (the issue there is outlined here: http://th3silverlining.com/2009/06/17/visualforce-component-ids-javascript/).
If you download the full listing at the end of the article (click on the last word I think) it is included there. That said I think that you’ve made a good point and it may be more confusing to leave it out so it’s in the main article too now. Good luck.
It seems that the code samples in this tutorial are incomplete. I don’t see the JavaScript in the middle of the Visualforce page on the datatable example, and the ids referenced in your jQuery code don’t match up with the components. I’m guessing that the JavaScript that defines “accountTableBodyId” and “pbsId” is missing from the VF page code?
Rob, I had left that part out intentionally as I was worried that since component Ids in JavaScript are tricky that code might draw the focus away from the jQuery plug-in (the issue there is outlined here: http://th3silverlining.com/2009/06/17/visualforce-component-ids-javascript/).
If you download the full listing at the end of the article (click on the last word I think) it is included there. That said I think that you’ve made a good point and it may be more confusing to leave it out so it’s in the main article too now. Good luck.
It seems that the code samples in this tutorial are incomplete. I don’t see the JavaScript in the middle of the Visualforce page on the datatable example, and the ids referenced in your jQuery code don’t match up with the components. I’m guessing that the JavaScript that defines “accountTableBodyId” and “pbsId” is missing from the VF page code?
It seems that the code samples in this tutorial are incomplete. I don’t see the JavaScript in the middle of the Visualforce page on the datatable example, and the ids referenced in your jQuery code don’t match up with the components. I’m guessing that the JavaScript that defines “accountTableBodyId” and “pbsId” is missing from the VF page code?
Hi,
i have a problem with pagination.con am displaying all contact records with pagination standard set controller.
here i put command link on contact records. my requirement is when i click on command link it will show it’s detaiiled page in visual force page.here i added one more pagination con1 clicking on next it will show next record detail page so on.
but am comparing param id con1 got one record only .
how can i solve my problem please anybody help me.
Thank you.
Hi,
i have a problem with pagination.con am displaying all contact records with pagination standard set controller.
here i put command link on contact records. my requirement is when i click on command link it will show it’s detaiiled page in visual force page.here i added one more pagination con1 clicking on next it will show next record detail page so on.
but am comparing param id con1 got one record only .
how can i solve my problem please anybody help me.
Thank you.
I am getting this Error
Error: Unknown page Template referenced by attribute template in in pagination at line 129 column 43
Even if I remove apex:composition tag
I am getting this Error
Error: Unknown page Template referenced by attribute template in in pagination at line 129 column 43
Even if I remove apex:composition tag
I am getting this Error
Error: Unknown page Template referenced by attribute template in in pagination at line 129 column 43
Even if I remove apex:composition tag
I have implemented the above code in my developer org.My question is that where the pagination comes into pictures?How I will achieve the pagination functionality.Data is displaying in a datatable or using repeat but pagination is not coming
I have the same error.
Error: Unknown page Template referenced by attribute template in in pagination at line 129 column 43
Please give any idea?