Pages

Wednesday, November 12, 2008

Adding Sorting Capability to PageBlockTable Component

In one of my previous posts I demonstrated how to add paging feature to your Visualforce Pages, in this article we will explore how we can add sorting option to the PageBlockTable component.

Challenges:
  • How to replace standard header text with a link that calls a controller method for sorting the data
  • How to implement the link in such a way to support sort direction Ascending and Descending features
  • How to view Ascending and Descending state of the columns
And this is one way of meeting the above challenges:
I first replace the standard header of the Column tag with a facet tag to include a commandLink component in it.

Then I select the column name to be pasted as parameter to the controller once the commandLink header is clicked on.

Then I add some condition to the Label of header to show "Ascending" and "Descending" icons.



<apex:page controller="PageBlockTableSortingCon" tabStyle="Account">
<apex:sectionHeader title="Accounts List with Sorting"></apex:sectionHeader>
<apex:form >
<apex:pageBlock title="" id="pageBlock">
<apex:pageBlockButtons location="top">
<apex:commandButton value="View" action="{!ViewData}" id="theButton" rerender="pageBlock"></apex:commandButton>
</apex:pageBlockButtons>
<apex:pageMessages ></apex:pageMessages>
<apex:pageBlockTable value="{!accounts}" var="a" rendered="{!NOT(ISNULL(accounts))}">
<apex:column>
<apex:facet name="header">
<apex:commandLink action="{!ViewData}" value="Account Name{!IF(sortExpression=='name',IF(sortDirection='ASC','▼','▲'),'')}" id="cmdSort">
<apex:param value="name" name="column" assignTo="{!sortExpression}" ></apex:param>
</apex:commandLink>
</apex:facet>
<apex:outputLink value="/{!a.Id}" target="_blank">{!a.Name}</apex:outputLink>
</apex:column>
<apex:column value="{!a.Phone}">
<apex:facet name="header">
<apex:commandLink action="{!ViewData}" value="Phone{!IF(sortExpression=='Phone',IF(sortDirection='ASC','▼','▲'),'')}">
<apex:param value="Phone" name="column" assignTo="{!sortExpression}" ></apex:param>
</apex:commandLink>
</apex:facet>
</apex:column>
<apex:column value="{!a.BillingCity}">
<apex:facet name="header">
<apex:commandLink action="{!ViewData}" value="Billing City{!IF(sortExpression=='BillingCity',IF(sortDirection='ASC','▼','▲'),'')}">
<apex:param value="BillingCity" name="column" assignTo="{!sortExpression}" ></apex:param>
</apex:commandLink>
</apex:facet>
</apex:column>
<apex:column value="{!a.BillingCountry}">
<apex:facet name="header">
<apex:commandLink action="{!ViewData}" value="Billing Country{!IF(sortExpression=='BillingCountry',IF(sortDirection='ASC','▼','▲'),'')}">
<apex:param value="BillingCountry" name="column" assignTo="{!sortExpression}" ></apex:param>
</apex:commandLink>
</apex:facet>
</apex:column>

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





And this how the controller look like:




public class PageBlockTableSortingCon {

private List<Account> accounts;
private String sortDirection = 'ASC';
private String sortExp = 'name';

public String sortExpression
{
get
{
return sortExp;
}
set
{
//if the column is clicked on then switch between Ascending and Descending modes
if (value == sortExp)
sortDirection = (sortDirection == 'ASC')? 'DESC' : 'ASC';
else
sortDirection = 'ASC';
sortExp = value;
}
}

public String getSortDirection()
{
//if not column is selected
if (sortExpression == null || sortExpression == '')
return 'ASC';
else
return sortDirection;
}

public void setSortDirection(String value)
{
sortDirection = value;
}

public List<Account> getAccounts() {
return accounts;
}


public PageReference ViewData() {
//build the full sort expression
string sortFullExp = sortExpression + ' ' + sortDirection;

//query the database based on the sort expression
accounts = Database.query('Select id, Name, BillingCity, BillingCountry, Phone from Account order by ' + sortFullExp + ' limit 1000');
return null;
}

}



25 comments:

  1. Great post Sam. Features like sort add to the usability of any app.

    ReplyDelete
  2. gr8 post .. awsome .. thats what exactly I wa slooking for ... :)

    I made slight simple modification by adding this parameter to Header Command Links :
    reRender="pageBlock"

    so as to make Sorting AJAX enabled .. instead of Full page refresh ...

    :)

    ReplyDelete
  3. I am happy that it worked well for you.
    Cheers,
    Sam

    ReplyDelete
  4. thank you for your good solution.
    It is very helpful to me.
    thanks~

    ReplyDelete
  5. Great post, thanks for the pointer! One minor note, sorting arrows usually "point" toward the "small" side of the sort, yours are pointing toward the large side of the sort. At least to match windows sorting arrow convention, they should be reversed.

    ReplyDelete
  6. this is a very good example. I already have a custom controller extension. How can I add another controller in my apex class to include sorting.
    I also have multiple pages/list where I need to use sorting.

    ReplyDelete
  7. Great article, i was looking for something like this for ages.
    thanks

    ReplyDelete
  8. Sam, what about just having the data in a related list sorted the way you want? e.g. case comments sorted newest-to-oldest?

    ReplyDelete
  9. hey Sam I need help on this i have used it to display child records and sort them. here is wat i have done.everythng comes well but it doesnt sort when i click it juss the same values.















    {!a.Name}























































    ------------------------------






    public class PageBlockTableSortingCon {






    transient private List con;
    private String sortDirection = 'ASC';
    private String sortExp = 'name';

    public String sortExpression
    {
    get
    {
    return sortExp;
    }
    set
    {
    //if the column is clicked on then switch between Ascending and Descending modes
    if (value == sortExp)
    sortDirection = (sortDirection == 'ASC')? 'DESC' : 'ASC';
    else
    sortDirection = 'ASC';
    sortExp = value;
    }
    }

    public String getSortDirection()
    {
    //if not column is selected
    if (sortExpression == null || sortExpression == '')
    return 'ASC';
    else
    return sortDirection;
    }

    public void setSortDirection(String value)
    {
    sortDirection = value;
    }

    public List getCollectorNotes() {
    return con;
    }


    public PageReference ViewData() {
    //build the full sort expression
    string sortFullExp = sortExpression + ' ' + sortDirection;

    //query the database based on the sort expression

    con = Database.query('Select id,Account__c,Collector__c,Dealer_ID__c,Follow_Up_Date__c,Note_Type__c,Peoplesoft_ID__c,Description__c, Name from Collector_s_Notes__c order by ' + sortFullExp + ' limit 1000');

    return null;

    }

    }

    ReplyDelete
  10. how to achive both paging and sorting at the same time

    ReplyDelete
  11. i am not getting what is value here ? is that a keyword ..or a property ..it is not declared anywhere?

    ReplyDelete
  12. Hi SAM, this it's very helpful to me, thx

    But, I'm pretty new and I don't understand well this part, can you explain this please??

    /apex:param value="name" name="column" assignTo="{!sortExpression}"/

    Why are you using the var "sortExpression" in this part?

    thanks for all

    ReplyDelete
  13. Hi SAM, this it's very helpful to me, thx

    But, I'm pretty new and I don't understand well this part, can you explain this please??

    /apex:param value="name" name="column" assignTo="{!sortExpression}"/

    Why are you using the var "sortExpression" in this part?

    thanks for all

    ReplyDelete
  14. Hi Sam, Your codes and knowledge are Excellent.

    ReplyDelete
  15. Thanks Sam, sorting helped me.

    ReplyDelete
  16. Hi Sam! I was able to do this but when I clicked the arrows, nothing happens.. Please help.. Thanks!

    ReplyDelete
  17. This comment has been removed by the author.

    ReplyDelete
  18. Hi Sam! I ran your code for my Object but it is giving me error "You may specify either a ''value'' attribute or a body for the column component, but not both"
    Pl. help me out, its urgent.

    ReplyDelete
  19. Trying copy and paste the code but not able to get result facing error problem

    ReplyDelete
  20. Thanks for the post.

    Do you know why during sorting it is always putting blank values at the top and then sorting.

    ReplyDelete
  21. can any one help me, i need the standard controller page- block table
    actions (First,Previous,Next,Last) in custom controller page -block table.
    mail to sf.harsha@gmail.com if any code there--
    Thanks in Advance

    ReplyDelete
  22. Thanks Sam! That was a nice workaround for table sorting and indeed very helpful.

    ReplyDelete
  23. Getting this Save error:

    You may specify either a ''value'' attribute or a body for the column component, but not both

    ReplyDelete
  24. Hi Sam,
    Thanks for the post. It's very helpful but is their any fast way to sort large number of records??

    ReplyDelete