Dynamically Sorting with Comparable Interface

I have seen several time questions regarding sorting in visual page, so I wrote simple example that show how to implement such requirement with the comparable interface.

I have visual page that show list of Case records.
The requirement is to allow sorting the list by clicking on the header of each column.

There are some techniques for achieving this functionality:
1.With JavaScript code inside the page.
2.Comparable interface (this example).
3.Order By in the SQL and re-running the query after each time the user click column header.

The javascript might be little complicate for people who not familiar with this language, the last one might be limited for some cases and require re-quering database each time, so I found the Comparable method as the most flexible and comfortable for most cases.


1.The controller for the page - vf_PageWithSorting


public class vf_PageWithSorting   {  

 public list<CaseWrp> caseWrpLst {get; set;}  
 public static String compareField {get; set;}  
 public static String sortOrder{get; set;}  

 public vf_PageWithSorting()  {  
  caseWrpLst = new list<CaseWrp>();  

  for(Case c : [ select Id, CaseNumber, Status, Priority, Subject from Case])  {  
   caseWrpLst.add(new CaseWrp(c));  
  }  
 }  

 public void sortWrpLst() {  
  caseWrpLst.sort();  
 }  

 public class caseWrp implements Comparable {  
  public Case caseRec {get; set;}  
  public Boolean selected {get; set;}  

  public caseWrp(Case c) {  
   caseRec = c;  
   selected = false;  
  }  

  public Integer compareTo(Object vCase) {  
   caseWrp caseToComp = (caseWrp )vCase;  

   if((String)caseRec.get(compareField) > (String)caseToComp.caseRec.get(compareField)) {
    return sortOrder.equals('asc') ? 1 : 0;  
   }
   else {
    return sortOrder.equals('asc') ? 0 : 1;  
   }
  }  
 }  
}  

The class have list of wrapper class - CaseWrpLst- that will be displayed in the page.

Also we define 2 static variables:
-compareField - should contain the name (API) of the field that should use for the sorting.
-sortOrder - the sort order (asc/desc).
Those 2 fields should be defined as static since they referenced from other class -CaseWrp- which use those fields for the sorting logic.

The sorting logic is in lines : 35-43. It compare 2 object caseWrp according to the field compareField. Returning 1 means the current object greater than the object he compare to.

In line 19 function sortWrpLst call function sort on the list of wrapper object.
We can automatically use the sort function since we define our class Comparable and implement the compareTo function. The sort function automatically use the compareTo function in the object.


2.The page - PageWithSorting


<apex:page controller="vf_PageWithSorting ">  
 <apex:form id="frm">  
  <apex:sectionHeader title="Case List with Sorting" >  
   <apex:pageBlock>   
    <apex:pageBlockTable value="{!caseWrpLst}" var="caseWrp">  

     <apex:column headerValue="Selected" width="50">  
      <apex:inputCheckbox value="{!caseWrp.selected}" />  
     </apex:column>  

     <apex:column>  
      <apex:facet name="header">  
       <apex:commandLink value="Case Number {!IF(compareField=='CaseNumber',IF(sortOrder='asc','▼','▲'),'')}" action="{!sortWrpLst}">  
        <apex:param name="compareField" value="CaseNumber" assignTo="{!compareField}" />  
        <apex:param name="orderType" value="{!IF(sortOrder='asc', 'desc', 'asc')}" assignTo="{!sortOrder}" />  
       </apex:commandLink>  
      </apex:facet>  
      <apex:outputField value="{!caseWrp.caseRec.CaseNumber}"/>  
     </apex:column>  

     <apex:column>  
      <apex:facet name="header">  
       <apex:commandLink value="Subject {!IF(compareField=='Subject',IF(sortOrder='asc','▼','▲'),'')}" action="{!sortWrpLst}">  
        <apex:param name="compareField" value="Subject" assignTo="{!compareField}" />  
        <apex:param name="orderType" value="{!IF(sortOrder='asc', 'desc', 'asc')}" assignTo="{!sortOrder}" />  
       </apex:commandLink>  
      </apex:facet>  
      <apex:outputField value="{!caseWrp.caseRec.Subject}"/>  
     </apex:column>  

     <apex:column>  
      <apex:facet name="header">  
       <apex:commandLink value="Status {!IF(compareField=='Status',IF(sortOrder='asc','▼','▲'),'')}" action="{!sortWrpLst}">  
        <apex:param name="compareField" value="Status" assignTo="{!compareField}" />  
        <apex:param name="orderType" value="{!IF(sortOrder='asc', 'desc', 'asc')}" assignTo="{!sortOrder}" />  
       </apex:commandLink>  
      </apex:facet>  
      <apex:outputField value="{!caseWrp.caseRec.Status}"/>  
     </apex:column>  

     <apex:column>  
      <apex:facet name="header">  
       <apex:commandLink value="Priority {!IF(compareField=='Priority',IF(sortOrder='asc','▼','▲'),'')}" action="{!sortWrpLst}">  
        <apex:param name="compareField" value="Priority" assignTo="{!compareField}" />  
        <apex:param name="orderType" value="{!IF(sortOrder='asc', 'desc', 'asc')}" assignTo="{!sortOrder}" />  
       </apex:commandLink>  
      </apex:facet>  
      <apex:outputField value="{!caseWrp.caseRec.Priority}"/>  
     </apex:column>  

    </apex:pageBlockTable>  
   </apex:pageBlock>  
  </apex:sectionHeader>  
 </apex:form>  
</apex:page>  

The page show all the data inside PageBlockTable.
Inside each column we define commandLink so the user can click on the column.
The title on the column is the name of the field + sign ▼ or ▲ if it is the current compareField.
The action on each link is to call the function sortWrpLst on the controller (which sort the list).
The apex:param inside the commandLink used to assign the relevant variable in the class, according to the field.


Result (after clicking the "Subject" column):

1 comment:

Retire of Permission on Profiles

If you are working as a Salesforce admin/developer you've probably heard somewhere that Salesforce is planning to make a significant cha...