Is there any native Apex
solution to get option to sort a column in apex data table?
3 Answers
If you are using apex:dataTable
then you can pre-sort the data in your SOQL query. See here for an example of using apex:dataTable: https://developer.salesforce.com/docs/atlas.en-us.pages.meta/pages/pages_compref_dataTable.htm
Using the query on that page as an example, you could sort it as follows:
public List<Account> getAccounts() {
if(accounts == null)
accounts = [SELECT name, owner.name FROM account ORDER BY name DESC LIMIT 10];
return accounts;
}
Notice I added the ORDER BY name DESC
which will then return the results of Accounts by Name in descending order.
The way I've always done this is with dynamic SOQL. Start with
public String sortField = {get;set;}
public String sortDirection {get;set;}
public List<Account> tableContents {get; set;}
public String paramFromPage {get; set;}
private String queryString = 'SELECT Id, Name FROM Account';
public myController(){
sortField = '';
sortDirection = '';
tableContents = Database.query(queryString + sortField + sortDirection);
}
Then the header for the <apex:dataTable/>
column can be a <apex:commandLink/>
that takes a parameter (like Name
), assigns it to sortField
, and sets the sortDirection
. As in:
VF:
<apex:commandLink value="Name">
<apex:param value="Name" assignTo="{!paramFromPage}"/>
</apex:commandLink>
APEX:
sortField = String.escapeSingleQuotes(paramFromPage); //to prevent SOQL injection
sortDirection = 'ASC NULLS LAST';
If you're interested, you can read more about SOQL injection here.
Then if they press the link in the column again, and the new sortField
is the same as the old sortField
, then leave it the way it is and change sortDirection
to DESC NULLS FIRST
and re-query for tableContents
.
An added benefit of doing it this way is that you can modify the dataTable
to support Field Sets without too much additional effort.
-
If you don't escape these sort variables, you expose an injection vulnerability.– Adrian Larson ♦Commented Feb 7, 2017 at 19:44
-
Ah, great point. Added a note about that in my answer. Commented Feb 7, 2017 at 19:57
-
Fair enough. Trying too hard to teach a man to fish, I suppose. I left the link in there to make myself feel better, but it's part of the actual snippet now. Commented Feb 7, 2017 at 20:13
-
-
Don't you have to give the
<apex:param>
tag aname
attribute for it to actually bind back to the server?– Adrian Larson ♦Commented Feb 7, 2017 at 20:19
The following code will show a VF page with two columns in a table :- Account ID and Account Name. Clicking on "Account Name" header in the table will cause sorting of the data in that column. If it is sorted in ascending order, then it will switch to descending order and vice-versa.
public class AccountSortHeader
{
public List<Account> allAcc {get;set;}
public String sortDirection {get;set;}
public AccountSortHeader()
{
sortDirection = 'asc';
String query = 'Select Id, name from Account order by Name ' + sortDirection;
allAcc = Database.query(query);
}
public pageReference sortAccNamecolumn()
{
if(sortDirection == 'asc')
{
sortDirection = 'desc';
}
else if(sortDirection == 'desc')
{
sortDirection = 'asc';
}
String query = 'Select Id, name from Account order by Name ' + sortDirection;
allAcc = Database.query(query);
return null;
}
}
VF page :-
<apex:page controller="AccountSortHeader">
<apex:form>
<apex:pageBlock>
<apex:pageBlockTable value="{!allAcc}" var="a" id="AccountData">
<apex:column headerValue="Account ID" value="{!a.Id}"/>
<apex:column value="{!a.Name}">
<apex:facet name="header">
<!-- Any facet whose name is header will apply to the header of this column in the pageBlockTable -->
<apex:outputPanel>
<apex:commandLink value="Account Name" action="{!sortAccNamecolumn}" reRender="AccountData"/>
</apex:outputPanel>
</apex:facet>
</apex:column>
</apex:pageBlockTable>
</apex:pageBlock>
</apex:form>
</apex:page>