Friday 14 November 2014

Pagination with Wrapper Class ( with maintaing the state of selected records)

Problem :-

1) One thing I noticed is the Checkboxes don’t maintain state in pagination with StandardSetController if you check one, go to the next page, then go back. Checkbox will uncheck again.

2) StandardSetController only support List of Sobject and SOQL as parameter. Some time in our case we did not use the SOQL and Sobject. We need to create Wrapper class and need to show that wrapper class with pagination on Visual force page.


Solution :- 

So If we use the StandardSetController, the check-boxes don’t maintain state if you check one and then go to the next page. To solve this problem I have implemented custom Iterator.

Even in StandardSetController constructor we cant sent List of Wrapper.



Please check Working on below link :-
http://amitblog-developer-edition.ap1.force.com/apex/CustomPaginationDemo


Step 1:- Create Wrapper Class :-


global class ContactWrapper
{
public Boolean isSelected {get;set;}
public Contact cont{get;set;}        
    public ContactWrapper(Contact cont,Boolean isSelected)
    {
        this.cont= cont;
        this.isSelected= isSelected;
    }
    
}



Step 2:-  Create A Custom Iterator class which should implement Iterator class 

global class  CustomIterable implements Iterator<list<ContactWrapper>>

   list<ContactWrapper> InnerList{get; set;}
   list<ContactWrapper> ListRequested{get; set;}

   Integer i {get; set;} 
   public Integer setPageSize {get; set;} 

   public CustomIterable(List<ContactWrapper> lstAccWr)
   {
       InnerList = new list<ContactWrapper >(); 
       ListRequested = new list<ContactWrapper >();     
       InnerList = lstAccWr;
       setPageSize = 10;
       i = 0; 
   }   

   global boolean hasNext(){ 
       if(i >= InnerList.size()) {
           return false; 
       } else {
           return true; 
       }
   } 
   
   global boolean hasPrevious(){ 
       system.debug('I am in hasPrevious' + i);
       if(i <= setPageSize) {
           return false; 
       } else {
           return true; 
       }
   }   

   global list<ContactWrapper > next(){       
       system.debug('i value is ' + i);
       ListRequested = new list<ContactWrapper >(); 
       integer startNumber;
       integer size = InnerList.size();
       if(hasNext())
       {  
           if(size <= (i + setPageSize))
           {
               startNumber = i;
               i = size;
           }
           else
           {
               i = (i + setPageSize);
               startNumber = (i - setPageSize);
           }
           
           system.debug('i value is =====' + i);
           system.debug('i value is 2==== ' + (i - setPageSize));
           
           for(integer start = startNumber; start < i; start++)
           {
               ListRequested.add(InnerList[start]);
           }
       } 
       return ListRequested;
   } 
   
   global list<ContactWrapper > previous(){      
       ListRequested = new list<ContactWrapper >(); 
       system.debug('i value is previous before =====' + i);
       integer size = InnerList.size(); 
       if(i == size)
       {
           if(math.mod(size, setPageSize) > 0)
           {    
               i = size - math.mod(size, setPageSize);
           }
           else
           {
               i = (size - setPageSize);
           } 
       }
       else
       {
           i = (i - setPageSize);
       }
       
       system.debug('i value is previous =====' + i);
       system.debug('i value is 2previous ==== ' + (i - setPageSize));
       
       for(integer start = (i - setPageSize); start < i; ++start)
       {
           ListRequested.add(InnerList[start]);
       } 
       return ListRequested;
   }   
}
    


Step 3:- Create controller class :-


public with sharing class CustomPaginationDemo
{

public List<ContactWrapper> lstWrapper {get;set;}
public List<ContactWrapper> lstSetController{get;set;}

CustomIterable obj;

    public CustomPaginationDemo() 
    {
        lstWrapper =  new List<ContactWrapper>();
        lstSetController = new List<ContactWrapper>();

        List<Contact> lstContact = [select id,name from Contact limit 20];
        
        for(Contact cont : lstContact )
        {
            lstWrapper.add(new ContactWrapper(cont ,false));
        }

        obj = new CustomIterable (lstWrapper); 
        obj.setPageSize = 5;
        next();         
    }
    
    
        public Boolean hasNext {
            get 
            {
                return obj.hasNext();
            }
            set;
        }
        
        public Boolean hasPrevious {
            get 
            {
                return obj.hasPrevious();
            }
            set;
        }
        
        public void next() 
        {
            lstSetController = obj.next();
        }
        
        public void previous() 
        {
            lstSetController = obj.previous();
        }
    
}


Step 4:- Create Visual Force Page :-

<apex:page controller="CustomPaginationDemo">
<apex:form >
 <apex:pageBlock id="ThePage">
 
    <apex:pageBlockSection columns="1">
 
      <apex:pageBlockTable value="{!lstSetController }" var="obj" >
             <apex:column headerValue="Select">
                <apex:inputCheckbox value="{!obj.isSelected}"/>
             </apex:column> 
             <apex:column value="{!obj.cont.Name}" headerValue="Name"/> 
      </apex:pageBlockTable>
    
        <apex:outputPanel >
           <apex:commandButton value="<<Previous" action="{!previous}" rendered="{!hasPrevious}" reRender="ThePage" />
           <apex:commandButton value="Next >>" action="{!next}" rendered="{!hasNext}" reRender="ThePage" />
        </apex:outputPanel>  
        
    </apex:pageBlockSection>
 </apex:pageBlock>
</apex:form>

</apex:page>



    



Related Link :-

Standardsetcontroller Reference:- https://www.salesforce.com/us/developer/docs/pages/Content/apex_pages_standardsetcontroller.htm

https://www.salesforce.com/us/developer/docs/pages/Content/apex_ApexPages_StandardSetController_constructors.htm

Standardsetcontroller Eaxmple :-
http://blog.jeffdouglas.com/2009/07/14/visualforce-page-with-pagination/

Iterable Class Detail:-
 https://www.salesforce.com/us/developer/docs/apexcode/Content/apex_classes_iterable.htm


Thanks
Amit Chaudhary

18 comments:

  1. Hi Amit,

    Nice post. But I am wondering, if it is possible to add 2 more methods "First" and "Last" Buttons/links to the page.

    ReplyDelete
  2. Nice solution Amit

    ReplyDelete
  3. This comment has been removed by the author.

    ReplyDelete
  4. Nice Post.

    Check below methods to show First and Last

    public void First()
    {
    while(getHasPrevious())
    if(iterator != null && getHasPrevious())
    listSetWrapperAccounts = iterator.previous();
    else
    break;
    }

    public void Last()
    {
    while(getHasNext())
    if(iterator != null && getHasNext())
    listSetWrapperAccounts = iterator.next();
    else
    break;
    }

    ReplyDelete
  5. I implemented the above same example, my pagination is working..but state is not getting retained.

    ReplyDelete
    Replies
    1. Same Code is working fine and even you can check same on below demo

      http://amitblog-developer-edition.ap1.force.com/apex/CustomPaginationDemo

      Please feel free to connect with me on my email id "amit.salesforce21@gmail.com"

      Delete
  6. Hi Amit. Can you please provide the test class for the above code which includes pagination from a wrapper class.Thanks!

    ReplyDelete
  7. Hi Amit,

    Can we somehow combine this with QueryLocator while querying ? Actually I want to persist the checkbox values while pagination but I have large number of records... few thousands

    ReplyDelete
  8. Hi Amit,

    Can we somehow combine this with QueryLocator while querying ? Actually I want to persist the checkbox values while pagination but I have large number of records... few thousands

    ReplyDelete
    Replies
    1. This comment has been removed by the author.

      Delete
    2. Prakash - For larger count of records, why don't you use transient variable, that will avoid view state issues and Amit's code is good to maintain your selections throughout your pagination.

      Delete
  9. what is the maximum number of records you tried with?

    ReplyDelete
    Replies
    1. I don't remember the count of records but definitely it was not more than 10,000 as I had the request to save those records as well. With salesforce limit of not saving more than 10K records, I had a hard limit on that.

      Delete
  10. Hi Amit,
    I AM getting constructor not defined error , while im implementing customiterable obj in controller class

    ReplyDelete
  11. hello
    thank you for this content

    ReplyDelete