JSF-Richfaces dynamic Sorting with rich:dataTable?

JSF-Richfaces dynamic Sorting with rich:dataTableDynamic sorting using GenericComparator for rich:dataTable, DataModel, SeralizedDataModel, its a key part of every JSF, Richfaces powered applications in the world.  If I say dynamic sorting; of-course you will have couple of thoughts or question in your mind, like this:

  • Dynamic sorting – how it works?
  • Which datatypes are supported in GenericComparator?
  • How to integrate dynamic sorting into JSF and Richfaces component in your application?

This is sorting solution applicable to rich:dataTable, rich:extendedDataTable, rich:rich:scrollableDataTable

Of-course, I will be answering all these questions in detail.  However If you have any queries, please leave a comment.


Dynamic sorting – how it works?

Dynamic sorting is performed using Generic Comparator in Java.  I have created simple and generic comparator class to do this key functionality of your application. Click here to know – how it works.


Datatypes supported in dynamic sorting?

Currently GenericComparator supports following data types.  I’m thinking to include support for Enum type as well in next update.

    • Integer
    • String
    • Long
    • Date
    • Float
    • Double

Integrate dynamic sorting into JSF/Richfaces

Previously I have written an article about How to do: JSF/Richfaces/Seam lazy/dynamic data loading with pagination?.  This article will give a complete idea of rich:dataTable & SerializedDataModel lazy data loading with pagination implementation.  In continuation to that, I will describing below about In which part of the code, you have to put GenericComparator to get a ability of dynamic sorting.

Kindly Note: Assuming you have read above mentioned article and aware of; how it has been implemented and how it has been extended.

Step 1

Health check! Purpose of this check to make you comfortable in below steps, following steps are extension or continuation of above article

  • Understood DynamicDataModel class implementation
  • Understood how SerializableDataModel class extended in above article
  • Understood how walk() method used in the above article

Good work congrats, you’re good to go!

Step 2

Declare following two local variables in DynamicDataModel class to manipulate Sorting values

private String sortField = null;
private boolean ascending = true;

Step 3

Download a GenericComparator.java from GitHub repo and place it in your project

Step 4

Go to DynamicDataModel class and implement org.richfaces.model.Modifiable interface like below:

public class DynamicDataModel extends SerializableDataModel implements Modifiable {
    ...
}

Modifiable interface provides one override method called modify(List<FilterField> filterFields, List<SortField2> sortFields); with help of modify method, we are going to determining Key values of sortField & sortOrder (ascending or descending)

@Override
public void modify(List<FilterField> filterFields, List<SortField2> sortFields) {
    if (null != sortFields && !sortFields.isEmpty()) {
        SortField2 sortField2 = sortFields.get(0);
        Expression expression = sortField2.getExpression();
        String expressionString = expression.getExpressionString();
        if (!expression.isLiteralText()) {
            expressionString =
		expressionString.replaceAll("[#|$]{1}\{.*?\.", "").replaceAll("\}", "");
        }

        this.sortField = expressionString;
        if (sortField2.getOrdering() == Ordering.ASCENDING) {
            this.ascending = true;
        } else if (sortField2.getOrdering() == Ordering.DESCENDING) {
            this.ascending = false;
        }
    }
}

As per article we are going to use only second parameter sortFields for sorting; filterFields we will see later in next article.

Step 5

Now key portion of sorting implementation comes to walk() method, that’s why we did a health check in step 1.  You can decide how you want to do implementation of sortField & ascending variable values in two possible way.

Possibility 1

After getting a List values from service/web service using getItemsByrange method you can apply sorting using GenericComparator class

// we can populate the data from Service Call/Web Service Call
// For eg. Data from database or Search results using Range values
// Define getItemsByrange() method to extract the required data
// by passing the range values
List sampleDataList = getItemsByrange(this.firstRow, this.numberOfRows.intValue());

// Apply Generic Comparator for sorting
Collection.sort(sampleDataList, new GenericComparator(this.sortField, this.ascending));

Possibility 2

Passing a sortField & ascending parameter value to getItemsByrange method and process it at service/web service side

// We can populate the data from Service Call/Web Service Call
// For eg. Data from database or Search results using Range values
// Define getItemsByrange() method to extract the required data
// by passing the range values

List sampleDataList = getItemsByrange(this.firstRow,
		this.numberOfRows.intValue(),
		this.sortField,
		this.ascending);

Completion view of Possibility 1

public void walk(FacesContext context, DataVisitor visitor, Range range,
		Object argument) throws IOException {

    // This is method we have to populate a data for DataTable
    // Range parameter provides the firstRow value and no. of rows value.
    // Extract those values to local variables
    this.firstRow = ((SequenceRange) range).getFirstRow();
    this.numberOfRows = ((SequenceRange) range).getRows();

    // We can populate the data from Service Call/Web Service Call
    // For eg. Data from database or Search results using Range values
    // Define getItemsByrange() method to extract the required data
    // by passing the range values
    List sampleDataList = getItemsByrange(this.firstRow,							  this.numberOfRows.intValue());

    // Apply Generic Comparator for sorting
    Collection.sort(sampleDatalist, new GenericComparator(this.sortField, this.ascending));

    // Now store the data to wrappedKeys and
    // wrappedData components for the framework to make use of.
    wrappedKeys = new ArrayList();
    if (!sampleDataList.isEmpty()) {
        for (SampleData item : sampleDataList) {
        wrappedKeys.add(item.getId());
        wrappedData.put(item.getId(), item);
        visitor.process(context, item.getId(), argument);
        }
    }
}

Step 6

We have completed the Java portion of sorting implementation, let’s move on to JSF/Richfaces code snippet.  Add following two attributes sortable & sortBy in the rich:column tag, this important to make rich column sortable

Note: sortBy attribute & sorting applicable to only var binding list in the rich:dataTable, rich:extendedDataTable and rich:rich:scrollableDataTable

<rich:column sortable="true" sortBy="#{item.firstName}">

When user clicks on First Name column on the page, walk() method receives the value which column has clicked and which sort order requested (asc or desc) throught sortField & ascending variable.


Downloads

  GenericComparator.java   DynamicDataModelWithSorting.java   SampleData.java

Completion

That’s all, you have successfully implemented the JSF-Richfaces dynamic Sorting with rich:dataTable!