Search

Tuesday, 16 August 2011

Multiple Object Pagination on 1 VF Page

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>&nbsp;</p>
               <apex:outputlabel styleclass="largeTitle">object1 Section</apex:outputlabel>
              <p>&nbsp;</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>&nbsp;</p>
             <apex:outputlabel styleclass="largeTitle">object2  Section</apex:outputlabel>
             <p>&nbsp;</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>

4 comments:

  1. Hi Steve,

    Thank You so much!

    ReplyDelete
  2. No problem NS

    If you'd like me to write about a specific subject please let me know.

    Id appreciate for you to encourage other people to follow my blog.

    ReplyDelete
  3. This comment has been removed by a blog administrator.

    ReplyDelete
  4. Hi Steve,

    I am trying to display 40K + records on visualforcepage without using pagination. Will your code support this feature? Please suggest me any work around for this case.

    ReplyDelete

Note: only a member of this blog may post a comment.