6 min read

It’s hard to find a web application that does not have a single table that presents the user with some data. Building these DataTables, although not very difficult, can be a daunting task because each of these tables must often support paging, sorting, filtering, and so on. Wicket ships with a very powerful component called the DataTable that makes implementing all these features simple and elegant. Because Wicket is component-oriented, once implemented, these features can be easily reused across multiple DataTable deployments. In this article, we will see how to implement the features mentioned previously using the DataTable and the infrastructure it provides.

Sorting

A common requirement, when displaying tabular data, is to allow users to sort it by clicking the table headers. Click a header once and the data is sorted on that column in ascending order; click it again, and the data is sorted in the descending order.

In this recipe, we will see how to implement such a behavior when displaying data using a DataTable component. We will build a simple table that will look much like a phone book and will allow the sorting of data on the name and e-mail columns:

Apache Wicket: Displaying Data Using DataTable

Getting ready

Begin by creating a page that will list contacts using the DataTable, but without sorting:

  1. Create Contact bean:

    Contact.java
    public class Contact implements Serializable {
    public String name, email, phone;
    // getters, setters, constructors2.

    
    
  2. Create the page that will list the contacts:

    HomePage.html
    <html>
    <body>
    <table wicket_id=”contacts” class=”contacts”></table>
    </body>
    </html>
    HomePage.java
    public class HomePage extends WebPage {
    private static List<Contact> contacts = Arrays.asList(
    new Contact(“Homer Simpson”, “[email protected]”, “555-1211”),
    new Contact(“Charles Burns”, “[email protected]”, “555-5322”),
    new Contact(“Ned Flanders”, “[email protected]”, “555-9732”));
    public HomePage(final PageParameters parameters) {
    // sample code adds a DataTable and a data providert hat
    uses the contacts list created above
    }
    }

    
    

How to do it…

  1. Enable sorting by letting DataTable columns know they can be sorted by using a constructor that takes the sort data parameter:

    HomePage.java

    List<IColumn<Contact>> columns = new
    ArrayList<IColumn<Contact>>();
    columns.add(new PropertyColumn<Contact>(Model.of(“Name”),
    “name”,”name”));
    columns.add(new PropertyColumn<Contact>(Model.of(“Email”),
    “email”, “email”));
    columns.add(new PropertyColumn<Contact>(Model.of(“Phone”),
    “phone”));

    
    
  2. Implement sorting by modifying the data provider:

    private static class ContactsProvider
    extends SortableDataProvider<Contact> {
    public ContactsProvider() {
    setSort(“name”, true);
    }
    public Iterator<? extends Contact>
    iterator(int first, int count) {
    List<Contact> data = new ArrayList<Contact>(contacts);
    Collections.sort(data, new Comparator<Contact>() {
    public int compare(Contact o1, Contact o2) {
    int dir = getSort().isAscending() ? 1 : -1;
    if (“name”.equals(getSort().getProperty())) {
    return dir * (o1.name.compareTo(o2.name));
    } else {
    return dir * (o1.email.compareTo(o2.email));
    }
    }
    });
    return data.subList(first,
    Math.min(first + count, data.size())).iterator();
    }
    public int size() {
    return contacts.size();
    }
    public IModel<Contact> model(Contact object) {
    return Model.of(object);
    }
    }

    
    

How it works…

DataTable supports sorting out of the box. Any column with the IColumn#getSortProperty() method that returns a non-null value is treated as a sortable column and Wicket makes its header clickable. When a header of a sortable column is clicked Wicket will pass the value of IColumn#getSortProperty to the data provider which should use this value to sort the data. In order to know about the sorting information the data provider must implement the ISortableDataProvider interface; Wicket provides the default SortableDataProvider implementation which is commonly used to implement sort-capable data providers. DataTable will take care of details such as multiple clicks to the same column resulting in change of sorting direction, so on.

Let’s examine how to implement sorting in practice. In step 1 and 2, we have implemented a basic DataTable that cannot yet sort data. Even though the data provider we have implemented already extends a SortableDataProvider, it does not yet take advantage of any sort information that may be passed to it.

We start building support for sorting by enabling it on the columns, in our case the name and the email columns:

List<IColumn<Contact>> columns = new ArrayList<IColumn<Contact>>();
columns.add(new PropertyColumn<Contact>(Model.of(“Name”), “name”,
“name”));
columns.add(new PropertyColumn<Contact>(Model.of(“Email”), “email”,
“email”));
columns.add(new PropertyColumn<Contact>(Model.of(“Phone”), “phone”));


We enable sorting on the columns by using the three-argument constructor of the PropertyColumn, with the second argument being the “sort data”. Whenever a DataTable column with sorting enabled is clicked, the data provider will be given the value of the “sort data”. In the example, only the name and e-mail columns have sorting enabled with the sort data defined as a string with values “name” and “e-mail” respectively.

Now, let’s implement sorting by making our data provider implementation sort-aware. Since our data provider already extends a provider that implements ISortableDataProvider we only need to take advantage of the sort information:

public Iterator<? extends Contact> iterator(int first, int count) {
List<Contact> data = new ArrayList<Contact>(contacts);
Collections.sort(data, new Comparator<Contact>() {
public int compare(Contact o1, Contact o2) {
int dir = getSort().isAscending() ? 1 : -1;
if (“name”.equals(getSort().getProperty())) {
return dir * (o1.name.compareTo(o2.name));
} else {
return dir * (o1.email.compareTo(o2.email));
}
}
});
return data.subList(first,
Math.min(first + count, data.size())).iterator();
}


First we copy the data into a new list which we can sort as needed and then we sort based on the sort data and direction provided. The value returned by getSort().getProperty() is the same sort data values we have defined previously when creating columns.

The only remaining task is to define a default sort which will be used when the table is rendered before the user clicks any header of a sortable column. We do this in the constructor of our data provider:

public ContactsProvider() {
setSort(“name”, true);
}


There’s more…

DataTable gives us a lot out of the box; in this section we see how to add some usability enhancements.

Adding sort direction indicators via CSS

DataTable is nice enough to decorate sortable <th> elements with sort-related CSS classes out of the box. This makes it trivial to implement sort direction indicators as shown in the following screenshot:

Apache Wicket: Displaying Data Using DataTable

A possible CSS style definition can look like this:

table tr th { background-position: right; background-repeat:no-repeat;
}
table tr th.wicket_orderDown {
background-image: url(images/arrow_down.png); }
table tr th.wicket_orderUp {
background-image: url(images/arrow_up.png); }
table tr th.wicket_orderNone {
background-image: url(images/arrow_off.png);


1 COMMENT

LEAVE A REPLY

Please enter your comment!
Please enter your name here