Visualforce Page with Pagination
July 14th, 2009
Salesforce.com introduced the StandardSetController in Winter ‘09 and I’m finally getting a chance to put it into use. The new pagination feature is pretty powerful and easy to use with standard as well as custom objects. Even though Jon Mountjoy has a good blog post here, there appears to be very little documentation or examples for pagination.
I threw together a small demo that allows you to page through the query results and select multiple items to process. Instead of simply returning the list of sObjects from the query locator’s current set, a collection of wrapper objects are returned enabling the user to check items for processing.
You can run this demo on my developer site.
PagingController.cls – Custom Controller
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | public with sharing class PagingController { List<categoryWrapper> categories {get;set;} // instantiate the StandardSetController from a query locator public ApexPages.StandardSetController con { get { if(con == null) { con = new ApexPages.StandardSetController(Database.getQueryLocator([Select Id, Name FROM Cat3__c Order By Name limit 100])); // sets the number of records in each page set con.setPageSize(5); } return con; } set; } // returns a list of wrapper objects for the sObjects in the current page set public List<categoryWrapper> getCategories() { categories = new List<categoryWrapper>(); for (Cat3__c category : (List<cat3__c>)con.getRecords()) categories.add(new CategoryWrapper(category)); return categories; } // displays the selected items public PageReference process() { for (CategoryWrapper cw : categories) { if (cw.checked) ApexPages.addMessage(new ApexPages.message(ApexPages.severity.INFO,cw.cat.name)); } return null; } // indicates whether there are more records after the current page set. public Boolean hasNext { get { return con.getHasNext(); } set; } // indicates whether there are more records before the current page set. public Boolean hasPrevious { get { return con.getHasPrevious(); } set; } // returns the page number of the current page set public Integer pageNumber { get { return con.getPageNumber(); } set; } // returns the first page of records public void first() { con.first(); } // returns the last page of records public void last() { con.last(); } // returns the previous page of records public void previous() { con.previous(); } // returns the next page of records public void next() { con.next(); } // returns the PageReference of the original page, if known, or the home page. public void cancel() { con.cancel(); } } |
CategoryWrapper.cls – Wrapper class for the Categories
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | public class CategoryWrapper { public Boolean checked{ get; set; } public Cat3__c cat { get; set;} public CategoryWrapper(){ cat = new Cat3__c(); checked = false; } public CategoryWrapper(Cat3__c c){ cat = c; checked = false; } public static testMethod void testMe() { CategoryWrapper cw = new CategoryWrapper(); System.assertEquals(cw.checked,false); CategoryWrapper cw2 = new CategoryWrapper(new Cat3__c(name='Test1')); System.assertEquals(cw2.cat.name,'Test1'); System.assertEquals(cw2.checked,false); } } |
Category_Paging.page – Visualforce page
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | <apex:page controller="PagingController"> <apex:form > <apex:pageBlock title="Paging through Categories of Stuff"> <apex:pageBlockButtons location="top"> <apex:commandButton action="{!process}" value="Process Selected"/> <apex:commandButton action="{!cancel}" value="Cancel"/> </apex:pageBlockButtons> <apex:pageMessages /> <apex:pageBlockSection title="Category Results - Page #{!pageNumber}" columns="1"> <apex:pageBlockTable value="{!categories}" var="c"> <apex:column width="25px"> <apex:inputCheckbox value="{!c.checked}"/> </apex:column> <apex:column value="{!c.cat.Name}" headerValue="Name"/> </apex:pageBlockTable> </apex:pageBlockSection> </apex:pageBlock> <apex:panelGrid columns="4"> <apex:commandLink action="{!first}">First</apex:commandlink> <apex:commandLink action="{!previous}" rendered="{!hasPrevious}">Previous</apex:commandlink> <apex:commandLink action="{!next}" rendered="{!hasNext}">Next</apex:commandlink> <apex:commandLink action="{!last}">Last</apex:commandlink> </apex:panelGrid> </apex:form> </apex:page> |
Related posts:
- Apex Search with Checkbox Results
- Use an Inline Visualforce Page with Standard Page Layouts
- Dependent Multilevel Selectlists
- Generate a Visualforce Page from an Existing Page Layout
- Embed a Flex Slider in a Visualforce Page
Categories: Apex, Salesforce, Visualforce





Great post Jeff.
One thing I noticed is the checkboxes don’t maintain state if you check one, go to the next page, then go back. I think it’s due to line 20 in your controller, as it recreates the List of wrapper objects with each page. You could use a second List and populate that with the checked object, then compare with each page.
All that said, this is really a helpful post to explain the StandardSetController. I think it’s a big mystery in Apex and lacks attention. Thanks for shedding some light.
Tom, I noticed that too but am going to save that for another post. Thanks for the comment!
Thanks for the post Jeff.
I tried to use the SetController to pull up PricebookEntries from a Pricebook. I get the error “List controllers are not supported for PricebookEntry”. Is there a work around for this?
Unfortunately there are a number of things that are not supported for objects like PricebookEntry, OpportunityLineItem, etc. You might want to post this on the Salesforce message board and possibly a product manager could give you more info.
Im trying to do something like this:
First Previous 1 2 3…10 Next Last
For me that is impossible
No Dynamic SOQL with this though is there :(
So I can’t exactly create a ’search’ field on a VF page and then display paginated results…. To me this addition only gets you around having to use / create views when using a list view other than that it’s pretty useless. Correct me if I’m wrong… PLEASE…
Ha… Nevermind.. it works :) I’m an idiot.
Nice post Jeff. I like the StandartSetController but I’ve found it inflexible in many cases so I built a concept called Paginators. Here’s an article I wrote about it: http://richardvanhook.wordpress.com/2009/08/03/visualforce-pagination-with-apex-lang/. Hope it helps.
Nice link Richard. I had a look at your pagination with apex-lang but couldn’t get it to work for sets larger than 1000 records. I assume a bit of tinkering would be needed to make it work for larger sets?
Hi nice work.
How we can handle 10000+ records in setcontroller? is beyond its limit. Really eager to know about this.
Hi Patrick, yes, the paginator code has same restriction as apex in that a list can only contain 1000 items. You could get around this via a list of lists but then of course, the paginator code would need to be modified. We need a class called BigList that would handle this for you – perhaps I’ll write one in the future!
Hi there,
I tried out your exam, everything worked great. I tried adding partial refresh by adding rerender attribute to the commandLink tag and now its not showing the ‘Previou’ button when I go th the second page. Do you know why this is not working?