In Salesforce you can easily paginate records on a single object
<apex:page standardController="Account" recordSetvar = "accounts" >
<apex:pageBlock title="ViewingAccounts">
<apex:form id="theForm">
<apex:pageBlockSection>
<apex:dataList var="a" value="{!accounts}" type="1">
{!a.name}
</apex:dataList>
</apex:pageBlockSection>
<apex:panelGrid columns="2">
<apex:commandLink action="{!previous}">Previous</apex:commandlink>
<apex:commandLink action="{!next}">Next</apex:commandlink>
</apex:panelGrid>
</apex:form>
</apex:pageBlock>
</apex:page>
I've highlighted the new bits in bold:
You can easily control the number of records displayed in each page (it defaults to 25), by writing an extension:
VF Page
<apex:page standardController="Account" extensions="tenPageSizeExt" recordSetvar
= "accounts" >
public class tenPageSizeExt {
public tenPageSizeExt(ApexPages.StandardSetControllercontroller){
controller.setPageSize(10);
}
}
But the problem occurs when you want to include multiple objects on a single page and paginate each object independent of each other
To demonstrate this I've created a VF page called GeneralSearch and Controller called GeneralSearchController.
The key thing is to use multiple ApexPages.StandardSetController and to use Database.getQueryLocator to iterate through the records
String qry = 'select Id,Name from Account where ....';
ApexPages.StandardSetController acct = new ApexPages.StandardSetController(Database.getQueryLocator(qry));
Here is some example code
public class EnumeratedValues {
public enum OpportunityEnum {Object1, Object2}
}
public with sharing class OppReporting {
//iterators
public ApexPages.StandardSetController object1{get; set;}
public ApexPages.StandardSetController object2{get; set;}
//the current page number for each object
public integer object1Pg{get; set;}
public integer object2Pg{get; set;}
//display results
public List<Opportunity> object1Return {get;set;}
public List<Opportunity> object2Return {get;set;}
//number of records to display comes from a custom setting
public integer numberRecordsToDisplay{get;set;}
public string setRecordsToDisplay{get;set;}
//pages to display for Task
public list<integer> object1StatusPagesToDisplay{get;set;}
public integer selectedPageObject1{get;set;}
//pages to display for object2 summary
public list<integer> object2PagesToDisplay{get;set;}
public integer selectedPageObject2{get;set;}
private Set<Id> newIDsSet;
public Map<ID,ID> object1IdToTaskID{get; set;}
public ID selectedObject1{get; set;}
//public Set<String> subjects;
public list<Opportunity> opps{get; set;}
//max pages to dislay
public long numberOfPagesToDisplayObject1{get; set;}
public long numberOfPagesToDisplayObject2{get; set;}
public list<object1List> allObject1List{get;set;}{allObject1List = new list<object1List>();}
public list<object2List> allObject2List{get;set;}{allObject2List = new list<object2List>();}
public OppReporting(){
//get the number of records to display on each page
numberRecordsToDisplay = 10;
}
//Task Navig
public void moveToPageObject1() {
object1.setPageNumber(selectedPageObject1);
object1Pg = object1.getPageNumber();
refreshOutput(EnumeratedValues.OpportunityEnum.Object1,object1);
}
//Object2 Summary Navig
public void moveToPageObject2() {
object2.setPageNumber(selectedPageObject2);
object2Pg = object2.getPageNumber();
refreshOutput(EnumeratedValues.OpportunityEnum.Object2,object2);
}
public PageReference doSearch() {
integer numberRecordsToDisplayTemp;//if this is not used numberRecordsToDisplay gets permanently set so user can only increase records per page not decrease
if (setRecordsToDisplay != null && setRecordsToDisplay != '')
numberRecordsToDisplayTemp = integer.valueof(setRecordsToDisplay);
else
numberRecordsToDisplayTemp = numberRecordsToDisplay;
//1st object
String qry;
//NOTE - Product2__c will have to change to Product2
integer rowlimit = limits.getLimitQueryRows();
qry = 'select Id,Primary_Agency_Buyer__c,Account.Name,Name from Opportunity limit :rowlimit';
//get number of records
list<Opportunity> object1AllRecords = Database.query(qry);
//get number of pages to display
decimal numberOfPagesToDisplay = decimal.valueof(object1AllRecords.size()) / decimal.valueof(numberRecordsToDisplayTemp);
//round up
numberOfPagesToDisplayObject1 = numberOfPagesToDisplay.round(ROUNDMODE);
object1StatusPagesToDisplay = new list<integer>();
//produce list of pages to display
for (integer i = 1;i<=numberOfPagesToDisplayObject1;i++){
object1StatusPagesToDisplay.add(i);
}
//need to get into iterator so Prev and Next buttons work on same data
object1 = new ApexPages.StandardSetController(Database.getQueryLocator(qry));
object1.setPageSize(numberRecordsToDisplayTemp);
//query the data to display
refreshOutput(EnumeratedValues.OpportunityEnum.Object1,object1);
//used to render correct section
object1Pg=1;
//2nd object
qry = 'select Id,Primary_Agency_Buyer__c,Primary_Agency_Buyer__r.Name,Name,Sum_Total_Price_del__c, Third_party_Stats_checked__c from Opportunity limit :rowlimit';
//get number of records
list<Opportunity> object2AllRecords = Database.query(qry);
//get number of pages to display
integer object2AllSize = object2AllRecords.size();
decimal numberOfPagesToDisplay2 = decimal.valueof(object2AllSize) / decimal.valueof(numberRecordsToDisplayTemp);
//round up
numberOfPagesToDisplayObject2 = numberOfPagesToDisplay2.round(ROUNDMODE);
object2PagesToDisplay = new list<integer>();
//produce list of pages to display
for (integer i = 1;i<=numberOfPagesToDisplayObject2;i++){
object2PagesToDisplay.add(i);
}
//need to get into iterator so Prev and Next buttons work on same data
object2 = new ApexPages.StandardSetController(Database.getQueryLocator(qry));
object2.setPageSize(numberRecordsToDisplayTemp);
//query the data to display
refreshOutput(EnumeratedValues.OpportunityEnum.Object2,object2);
//used to render correct section
object2Pg=1;
return null;
}
public void refreshOutput(EnumeratedValues.OpportunityEnum OpportunityEnumType,ApexPages.StandardSetController std){
newIDsSet = new Set<Id>();
for (sObject eachRec : (List<sObject>)std.getRecords())
newIDsSet.add((ID)eachRec.get('id'));
system.debug('size refreshOutput ' + newIDsSet.size());
Task[] allTks;
OpportunityLineItem[] thisopplines;
if (OpportunityEnumType == EnumeratedValues.OpportunityEnum.Object1){
object1Return = [select Id,Primary_Agency_Buyer__c,Account.Name,Name from Opportunity where Id In :newIDsSet];
//Build list of object1List wrappers to easily display on page
object1List newObject1List;
allObject1List.clear();
for (Opportunity eachopp: object1Return){
allTks=eachopp.Tasks;
thisopplines = eachopp.OpportunityLineItems;
for (OpportunityLineItem eachoppline: eachopp.OpportunityLineItems){
newObject1List = new object1List(<<Add each value to wrapper class>>);
allObject1List.add(newObject1List);
}
}
}else if (OpportunityEnumType == EnumeratedValues.OpportunityEnum.Object2){
object2Return = [select Id,Primary_Agency_Buyer__c,Account.Name,Name,Sum_Total_Price_del__c,Campaign_Start_Date__c,Campaign_End_Date__c,Complexity__c,Complexity_explanation__c, Third_party_Stats_checked__c from Opportunity where Id In :newIDsSet];
thisopplines = eachopp.OpportunityLineItems;
for (OpportunityLineItem eachoppline: eachopp.OpportunityLineItems){
newObject2List = new object2List((<<Add each value to wrapper class>>);
allObject2List.add(newObject2List);
}
}
}
}
public class object1List{
public object1List(String addID, …){
this.thisID=addID;
<<Add more>>
}
public String thisID{get;set;}
<<Add more>>
}
public class object2List{
public object2List(String addID, … ){
this.thisID=addID;
<<Add more>>
}
public String thisID{get;set;}
<<Add more>>
}
}
<apex:page>
<apex:outputPanel rendered="{!object1StatusDisplay}" >
<p> </p>
<apex:outputlabel styleclass="largeTitle">object1 Section</apex:outputlabel>
<p> </p>
<apex:outputPanel id="currentobject1Page" >
<apex:outputlabel >Current Page {!object1Pg}</apex:outputlabel>
</apex:outputPanel>
<apex:pageBlockSection >
<apex:pageBlockTable var="object1Rec" value="{!allobject1List}" >
<apex:column headerValue="Agency">
<apex:commandLink target="_blank" action="/{!object1Rec.thisID}" value="{!object1Rec.thisAgency}"/>
</apex:column>
</apex:pageBlockTable>
</apex:pageBlockSection>
<apex:commandLink styleclass="rightspace" action="{!moveToPageobject1}" >First
<apex:param name="selectedPageobject1" assignTo="{!selectedPageobject1}" value="1" />
</apex:commandlink>
<apex:commandLink styleclass="rightspace" action="{!moveToPageobject1}" >Previous
<apex:param name="selectedPageobject1" assignTo="{!selectedPageobject1}" value="{!selectedPageobject1 - 1}" />
</apex:commandlink>
<apex:commandLink styleclass="rightspace" action="{!moveToPageobject1}" >Next
<apex:param name="selectedPageobject1" assignTo="{!selectedPageobject1}" value="{!selectedPageobject1 + 1}" />
</apex:commandlink>
<apex:commandLink styleclass="rightspace" action="{!moveToPageobject1}" >Last
<apex:param name="selectedPageobject1" assignTo="{!selectedPageobject1}" value="{!numberOfPagesToDisplayobject1}" />
</apex:commandlink>
<br />
<apex:outputPanel layout="block" styleclass="scrollNavig">
<apex:repeat value="{!object1StatusPagesToDisplay}" var="pgs" >
<apex:commandLink styleclass="rightspace" id="object1Link" action="{!moveToPageobject1}" >{!pgs}
<apex:param name="selectedPageobject1" assignTo="{!selectedPageobject1}" value="{!pgs}" />
</apex:commandlink>
</apex:repeat>
</apex:outputPanel>
</apex:outputPanel>
<apex:outputPanel rendered="{!object2Display}" >
<p> </p>
<apex:outputlabel styleclass="largeTitle">object2 Section</apex:outputlabel>
<p> </p>
<apex:outputPanel id="currentobject2Page" >
<apex:outputlabel >Current Page {!object2Pg}</apex:outputlabel>
</apex:outputPanel>
<apex:pageBlockSection >
<apex:pageBlockTable var="object2Rec" value="{!allobject2List}" >
<apex:column headerValue="Agency">
<apex:commandLink target="_blank" action="/{!object2Rec.thisID}" value="{!object2Rec.thisAgency}"/>
</apex:column>
<apex:column headerValue="ID">
<apex:outputLabel value="{!object2Rec.thisID}"/>
</apex:column>
</apex:pageBlockTable>
</apex:pageBlockSection>
<apex:commandLink styleclass="rightspace" action="{!moveToPageobject2}" >First
<apex:param name="selectedPageobject2" assignTo="{!selectedPageobject2}" value="1" />
</apex:commandlink>
<apex:commandLink styleclass="rightspace" action="{!moveToPageobject2}" >Previous
<apex:param name="selectedPageobject2" assignTo="{!selectedPageobject2}" value="{!selectedPageobject2 - 1}" />
</apex:commandlink>
<apex:commandLink styleclass="rightspace" action="{!moveToPageobject2}" >Next
<apex:param name="selectedPageobject2" assignTo="{!selectedPageobject2}" value="{!selectedPageobject2 + 1}" />
</apex:commandlink>
<apex:commandLink styleclass="rightspace" action="{!moveToPageobject2}" >Last
<apex:param name="selectedPageobject2" assignTo="{!selectedPageobject2}" value="{!numberOfPagesToDisplayobject2}" />
</apex:commandlink>
<br />
<apex:outputPanel layout="block" styleclass="scrollNavig">
<apex:repeat value="{!object2PagesToDisplay}" var="pgs" >
<apex:commandLink styleclass="rightspace" action="{!moveToPageobject2}" >{!pgs}
<apex:param name="selectedPageobject2" assignTo="{!selectedPageobject2}" value="{!pgs}" />
</apex:commandlink>
</apex:repeat>
</apex:outputPanel>
</apex:outputPanel>
</apex:outputPanel>
</apex:form>
</apex:pageBlock>
</apex:page>