Sunday, 25 November 2012

Salesforce Pagination Using OFFSET keyword in SOQL

As per salesforce Governor limitations  we can't get more than 1000 records in visualforce page. To display large number of records we can use pagination using OFFSET keyword in controller. OFFSET is use full feature for pagination.


Apex Controller:

public class PaginationController{
    // initial query string for contact
    String queryString = 'Select Id,FirstName,LastName,Email,Account.Name from Contact';
    
    Integer queryLimit;
    Integer offset;
    
    // for active and deactive page naviagator
    public Boolean firstOff{set;get;}    // previous part
    public Boolean lastOff{set;get;}     // next part
    
    public String limits{set;get;}
    public Integer pageNumber{set;get;}
    
    Integer listSize;    // for total contact size
    
    // constructor
    public PaginationController(){
        firstOff = false;
        queryLimit = 10;
        offset = 0;
        limits = '10';
        pageNumber = 1;
        
        aggregateResult res = [select COUNT(id) cnt from Contact ];
        
        // fill size of all contact
        listSize = Integer.valueOf(res.get('cnt'));
        
        // initialy check page more then 1 or not
        if(listSize > queryLimit) lastOff = true;
        else lastOff = false;
    }
    
    // get record according to limit and offset
    public List<Contact> getRecords(){
       return (List<Contact>)database.query(queryString+' LIMIT '+queryLimit+' OFFSET '+offset);
    }
    
    // navigate on next page
    public void next(){
        offset += queryLimit;
        if(offset+queryLimit >= listSize) lastOff = false;
        firstOff = true;
        pageNumber++;
    }
    
    // navigate on previous page
    public void previous(){
        if(offset-queryLimit <= 0){
            offset = 0;
            firstOff = false;
        }
        else offset -= queryLimit;
        lastOff = true;
        pageNumber--;
    }
    
    // switch on first page
    public void first(){
        offset = 0;
        firstOff = false;
        lastOff = true;
        
        pageNumber = 1;
    }
    
    // switch on last page
    public void last(){
        // set page number of and offset
        if(Math.Mod(listSize,queryLimit) == 0){
            offset = listSize-queryLimit;
            pageNumber = listSize/queryLimit;
        }
        else{
            offset = (listSize/queryLimit)*queryLimit;
            pageNumber = (listSize/queryLimit)+1;
        }
        
        lastOff = false;
        firstOff = true;
    }
    
    // for record limits
    public List<SelectOption> getItems(){
        List<SelectOption> options = new List<SelectOption>();
        options.add(new SelectOption('10','10'));
        options.add(new SelectOption('20','20'));
        options.add(new SelectOption('50','50'));
        options.add(new SelectOption('100','100'));
        return options;
    }
    
    // change query limit
    public void changeLimit(){
        // set query limit
        queryLimit = Integer.valueOf(limits);
        
        offset = 0;
        firstOff = false;
        
        // initialy check page more then 1 or not
        if(listSize > queryLimit) lastOff = true;
        else lastOff = false;
        
        // set page number
        pageNumber = 1;
    }
    
    // for show current record numbers
    public String getRecordInfo(){
        integer lastLimit;
        if(offset+queryLimit > listSize) lastLimit = listSize;
        else lastLimit = offset+queryLimit;
        return (offset+1) + ' - ' + lastLimit + ' of '+listSize;
    }
    
    // return total page number
    public Integer getTotalPage(){
        if(Math.Mod(listSize,queryLimit) == 0) return listSize/queryLimit;
        else return (listSize/queryLimit)+1;
    }
    
    // for direct page switching
    public void pageNavigation(){
    
        /* if user enter more then number ot total page number than
           set the value last page number in PageNumber. */
        if(Math.Mod(listSize,queryLimit) == 0 && pageNumber > listSize/queryLimit)
            pageNumber = listSize/queryLimit;    
        else if(pageNumber > (listSize/queryLimit)+1)
            pageNumber = (listSize/queryLimit)+1;
        
        // set offset according to pageNumber    
        if((pageNumber-1)*queryLimit < 0) offset = 0;
        else offset = (pageNumber-1)*queryLimit;    
        
        /* if pageNumber is 1 than deactive previous navigator
           else if pageNumber is o tha set the value of pageNumber is 1
           else if pageNumber is more than 1 active next navigator
        */
        if(pageNumber == 1) firstOff = false;
        else if(pageNumber == 0) pageNumber = 1;
        else if(pageNumber > 1) firstOff = true;
        
        // user enter last number of pagenumber than deactive next navigator
        if(Math.Mod(listSize,queryLimit) == 0){
            if(pageNumber == listSize/queryLimit) lastOff = false;
            else lastOff = true;
        }
        else{
            if(pageNumber == (listSize/queryLimit)+1) lastOff = false;
            else lastOff = true;
        }
    }
}


Visualforce Page:

<apex:page controller="PaginationController"> 
   <apex:form >     
      <apex:pageBlock id="pgb" title="Accounts Details">                    
<apex:actionStatus id="status">            
  <apex:facet name="start">                
 <div style="width: 1300px;">                                      
 <img src="/img/loading24.gif" style="vertical-align:middle;"/>                    
 <span style="margin-left: 10px; font-size:12px; font-weight: bold; color:#000000;">Please wait...</span> 
 </div>
 </apex:facet>        
</apex:actionStatus>        
<apex:actionFunction name="first" action="{!first}" status="status" reRender="pgb"/>        
<apex:actionFunction name="last" action="{!last}" status="status" reRender="pgb"/>                         
<apex:actionFunction name="next" action="{!next}" status="status" reRender="pgb"/>                           
<apex:actionFunction name="previous" action="{!previous}" status="status" reRender="pgb"/>        
<apex:actionFunction name="changeLimit" action=" {!changeLimit}" status="status" reRender="pgb"/>               
<apex:actionFunction name="callAction" action="{!pageNavigation}" status="status" reRender="pgb"/>        

         <div id="scroll" style="height: 300px; width: 1300px;overflow:auto;">           
<apex:pageBlockTable value="{!records}" var="con" id="pgbt">            
<apex:column value="{!con.FirstName}"/>                          
<apex:column value="{!con.LastName}"/>                            
<apex:column value="{!con.Account.Name}"/>                        
<apex:column value="{!con.Email}"/>                        
</apex:pageBlockTable>        
         </div> <br></br><br></br>        
<div style="width:750px;">            
<span>                
<apex:outputLabel value="{!recordInfo}"/>                        
<apex:selectList value="{!limits}" size="1" onchange="changeLimit();return false;"> 
<apex:selectOptions value="{!items}"/>                
</apex:selectList>            
</span>            

<span style="margin: 0 200px;">                
            <span style="margin: 0 3px;">                                      
<apex:outputPanel rendered="{!firstOff}">                        
<img src="/s.gif" onclick="first();return false;" style="cursor:pointer; cursor:hand; background- image:Url('/img/paginationArrows.gif');background-position: 0 1px;background-repeat: no-repeat;height:10px;width: 9px"/
</apex:outputPanel>
<apex:outputPanel rendered="{!(!firstOff)}">                        
<img src="/s.gif" style="cursor:text; background-image:url('/img/paginationArrows.gif');background-position: 0-10px;background-repeat: no-repeat;height: 10px;width: 9px;"/>                                       
</apex:outputPanel>                
             </span>                
<span style="margin: 0 3px;">                    
<apex:outputPanel rendered="{!firstOff}">                        
<img class="prev" src="/s.gif" onclick="previous();return false;" style="cursor:pointer; cursor:hand;background-image: url('/img/paginationArrows.gif'); background-position: -10px 1px;background-repeat: no-repeat;height: 10px;margin: 0; padding: 0;width: 9px;"/>                        
<apex:outputLabel value="Previous"  style="cursor:pointer; cursor:hand;" onclick="previous();return false;"/>
</apex:outputPanel>                    
<apex:outputPanel rendered="{!(!firstOff)}">                        
<img src="/s.gif" style="cursor:text; background-image: url('/img/paginationArrows.gif');background-position: -10px -10px;background-repeat: no-repeat;height: 10px;margin: 0;padding: 0;width: 9px;"/>                        
<apex:outputLabel value="Previous"  style="cursor:text; color: #A8A8A8"/>                    </apex:outputPanel>                </span>                
<span style="margin: 0 3px;">                    
<apex:outputPanel rendered="{!lastOff}">                        
<apex:outputLabel value="Next" style="cursor:pointer; cursor:hand;" onclick="next();return false;"/>     
<img src="/s.gif" onclick="next();return false;" style="cursor:pointer; cursor:hand; background-image: url('/img/paginationArrows.gif');background-position: -17px 1px; background-repeat: no-repeat;height: 10px; width: 9px;"/>                    
</apex:outputPanel>                    
<apex:outputPanel rendered="{!(!lastOff)}">                        
<apex:outputLabel value="Next" style="cursor:text; color: #A8A8A8"/>                        
<img src="/s.gif" style="cursor:text; background-image: url('/img/paginationArrows.gif');background-position: -17px -10px;background-repeat: no-repeat;height: 10px;width: 9px;"/>                    
</apex:outputPanel>                
</span>                
<span style="margin: 0 3px;">                    
<apex:outputPanel rendered="{!lastOff}">                        
<img src="/s.gif" onclick="last();return false;" style="cursor:pointer; cursor:hand; background-image: url('/img/paginationArrows.gif'); background-position: -27px 1px;background-repeat: no-repeat;height: 10px;width: 9px;"/>                    
</apex:outputPanel>                    
<apex:outputPanel rendered="{!(!lastOff)}">                        
<img src="/s.gif" style="cursor:text; background-image: url('/img/paginationArrows.gif');background-position: -27px -10px;background-repeat: no-repeat;height: 10px;width: 9px; "/>                    
</apex:outputPanel>                
</span>            
</span>            
<span style="margin: 0 -80px;">                
<apex:outputLabel value="Page"/>                
<apex:inputText id="pageNo" value="{!pageNumber}" style="width:20px; text-align:center" size="3" onkeydown="return runScript(event);"/>                
<apex:outputLabel value="of {!totalPage}"/>            
</span>        
</div>    
</apex:pageBlock>    
<script>        
function runScript(obj){            
//alert(obj.keyCode);            
if(obj.keyCode == 13){                
callAction();   // call action function                
return false;            
}
else if((obj.keyCode > 34 && obj.keyCode < 40) || (obj.keyCode > 95 && obj.keyCode < 106) || (obj.keyCode > 47 && obj.keyCode < 58) || obj.keyCode == 8 || obj.keyCode == 46 ){  
return true;            
}else{ 
return false;            
}       
}    
</script> 
</apex:form>
</apex:page>

2 comments:

  1. Good one thanks. It will help if you could format the VF page though.

    ReplyDelete