[SalesForce] Sorting List in descending order

I have created a th/td HTML table where Wrapper class List is already sorted with Comparable interface.

Requirement – User should be able to sort it in descending order based on the same field as well as back to ascending order if required.

What would be the options for doing this change?

  1. A select list option with ascending/descending and calling method through ActionFunction?
  2. Anything like commandLink possible in HTML table where user clicks the label of the column to be sorted and they alternately sort as asc and desc?
  3. Any other suggestions ?

Updating code :

Obj To Compare method

  public ProdWrapper(){
    }
    public ProdWrapper(Integer experienceNumberInt){
        this.AccountNumber = AccountNumber ;

    }
    public Integer compareTo(Object ObjToCompare) {
        ProdWrapper compareNum = (ProdWrapper)ObjToCompare;
         if (AccountNumber > compareExpNum .AccountNumber ) {
    return ascending ? 1 : -1;
} else if(AccountNumber < compareExpNum .AccountNumber ) {
    return ascending ? -1 : 1;
} else {
    return 0;
}      
}      

CommandLink

<th><apex:commandLink value="Account #" action="{!changeSort}" ><apex:param value="exp"/></apex:commandLink></th>

Best Answer

If you invert the sign of your Comparable, you'll get descending order. Depending on your exact requirements, this is usually pretty easy. Consider the following code:

public class MyController {
  public Boolean sortAsc { get; set; }
  public String sortField { get; set; }

  // Static vars don't persist, so we use backing variables
  Boolean mSortAsc;
  String mSortField;

  // What we display on the page
  public Wrapper[] WrapperList { get; set; }
  public class Wrapper implements Comparable {
    // Implementation can be whatever you need
    public Integer compareTo(Object other) {
      Wrapper o = (Wrapper)other;
      Integer baseSortValue = ...; // calculate normal value
      return baseSortValue * (MyController.sortAsc? 1: -1); // Multiply by -1 to invert sort;
    }
  }
  public void changeSort(String field) {
    // Set static vars
    sortAsc = mSortAsc;
    sortField = mSortField;
    // Set asc on field change, otherwise toggle
    sortAsc = field != sortField || !sortAsc; 
    sortField = field;
    WrapperList.sort();
    // And store for next sort
    mSortAsc = sortAsc;
    mSortField = sortField;
  }
}

I've left out some details, obviously, but this should point you in the right direction. Generally, I use apex:commandLink in the header cells to call changeSort, which takes care of all of the logic.


Edit: More Code

To sort by a column, just set the parameter for which field you wish to sort:

<apex:column >
    <apex:facet name="header">
        <apex:commandLink status="status" action="{!resort}" reRender="form">
            <apex:param assignTo="{!newSortOrder}" value="Owner.Name" />
            Assigned To {!if(sortField='Owner.Name',if(sortAsc,'▲','▼'),'')}
        </apex:commandLink>
    </apex:facet>
    <apex:outputField value="{!record.Owner.Name}">
        <apex:inlineEditSupport />
    </apex:outputField>
</apex:column>

In the controller, there is a public String sortField { get; set; } and public Boolean sortAsc { get; set; }; the former is set by apex:param, the latter is used by the resort method (above called changeSort). This particular implementation uses a SOQL ORDER BY clause, but you can use dynamic SObject methods to use the Comparable interface.

Also, see my answer on this question for how you could use an Interface to define which field is sorted (basically, you'd create a bunch of sorting interfaces, then select one to use). For example:

public compareTwo sortOrder;

public class Wrapper implements Comparable {
    public Integer compareTo(Object other) {
        return (sortAsc? 1: -1) * sortOrder.compare(this, (Wrapper)other);
    }
}

public interface compareTwo {
    Integer compare(Wrapper item1, Wrapper item2);
}

public class AccountNumberSort implements compareTwo {
    public Integer compare(Wrapper item1, wrapper item2) {
        return item1.AccountNumber.compareTo(item2.AccountNumber);
    }
}
public class NameSort implements compareTwo {
    public Integer compare(Wrapper item1, wrapper item2) {
        return item1.Name.compareTo(item2.Name);
    }
}

...

public void changeSort() {
    sortAsc = sortField != mSortField || !sortAsc;
    mSortField = sortField;
    mSortAsc = sortAsc;

    Map<String, Type> fieldMap = new Map<String, Type> {
        'AccountNumber' => AccountNumberSort.class,
        'Name' => NameSort.class
    };
    sortOrder = (compareTwo)fieldMap.get(sortField).newInstance();
    wrapperList.sort();
}
Related Topic