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):

Using Apex Class from Visual Flow

Visual flow it's a very nice and useful tool for creating process with minimum time effort.

However, there are cases where you can implement most of your requirement easily with the flow, except small part of the process which can be done only with code.
For that reason we can connect our flow to apex class, and from there we can do almost anything.

I will show it with simple example:
Visual flow to close case (update the status to closed) instead of the standard Close Case button, and sending email to inform specific person that the case was closed.
The last part can be done with apex class (actually it can also be done with workflow, but for the example I'll use apex code).


1.Creating the class.

This class must implement interface Process.Plugin, and must implement 2 methods:

Process.PluginResult invoke(Process.PluginRequest request)
            This is the function that the flow call from the class.

Process.PluginDescribeResult describe()
            this function describe to the flow which data the plugin need to receive.


global with sharing class cls_FlowSendEmailCase implements Process.Plugin {  

 //The main method to be implemented. The Flow calls this at runtime.   
 global Process.PluginResult invoke(Process.PluginRequest request) {   
  String caseId = (String) request.inputParameters.get('vCaseID');  
  String emailAddress = (String) request.inputParameters.get('vEmailAddress');  

  sendCaseEmail(caseId, emailAddress );  

  //return to Flow   
  Map<String,Object> result = new Map<String,Object>();  
  return new Process.PluginResult(result);   
 }   

 //Returns the describe information for the interface   
 global Process.PluginDescribeResult describe()  {   

  Process.PluginDescribeResult result = new Process.PluginDescribeResult();  
  result.Name = 'CloseCase';  
  result.Tag = 'Name';  

  result.inputParameters =new List<Process.PluginDescribeResult.InputParameter>();  

  result.inputParameters.add(  
   new Process.PluginDescribeResult.InputParameter('vCaseID',  
   Process.PluginDescribeResult.ParameterType.STRING, true));  

  result.inputParameters.add(  
   new Process.PluginDescribeResult.InputParameter('vEmailAddress',  
   Process.PluginDescribeResult.ParameterType.STRING, true));  

  return result;  
 }  

 public void sendCaseEmail(String caseId, String emailAddress) {  
  Case caseRec = [SELECT id, caseNumber FROM Case WHERE id=:caseId];  

  Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();  
  mail.setToAddresses(new String[] {emailAddress});  
  mail.setSubject('Case Closed. ' + caseRec.caseNumber);  
  mail.setPlainTextBody('This case has been closed ');  

  Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });  
 }  
}  



In this example the class received 2 parameters: the case ID and the email address (line 6-7).

In line 9, we call function sendCaseEmail, to send the email.

After creating such class (that implement Process.Plugin), we will see it in the flow designer, and will be able to use it by dragging it from the Palette tab to our flow.

2.Creating the flow.

This is our flow



First It will show kind of information message + option to send email and filling the email address.


Next we will first update the case to closed, and send email depend on the checkbox that user tag.

If the user select the check-box (equal true), then the flow will get to the CloseCase Send Case Email (with the plugin icon) and call the function invoke inside the class.

When we double clicking this square, we will show the variable we defined in the describe method, and we will be able to assign values to them.

The caseId in the class get the case id of the flow (should pass in the URL when calling the flow).
The email address get the email from the user input (stage 1 in the flow).



3.Finally add custom button in Case, that will call this flow.

The button will call URL:
/flow/CloseCase?vCaseID={!Case.Id}&retURL={!Case.Id}

The vCaseID is variable inside the flow (name must be exactly the same).

4.The final result:


Filling the email address and clicking 'Next'

Confirmation message

The email received and the case closed.

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...