Exploring ICEfaces ACE Datatable Component (1)

3 Comments

DataTable

The Datatable component is absolutely one of the most important (if not the most) components provided by ICEfaces, both in the old ICE components and the new ACE components, in this post I’m going to explore the capabilities of the ACE Datatable component.


Technologies

  • ICEfaces 3.3.0
  • JSF 2.1.21

Here’s an index of the discussed topics in part 1:

1- Single Row Select
2- Multiple Row Select
3- Cell Select
4- Cell Select with AJAX
5- Pagination
6- Sorting

In the beginning, I’m going to create a Person class, every row in the Datatable will represent a Person.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package com.alibassam.blog;
 
public class Person {
	// Variables
	private Integer id;
	private String name;
	private String email;
 
	// Constructor
	public Person(Integer id, String name, String email) {
		this.id = id;
		this.name = name;
		this.email = email;
	}
 
	// Get
	public Integer getId() {
		return id;
	}
	public String getName() {
		return name;
	}
	public String getEmail() {
		return email;
	}
 
	// Set
	public void setId(Integer id) {
		this.id = id;
	}
	public void setName(String name) {
		this.name = name;
	}
	public void setEmail(String email) {
		this.email = email;
	}
}

Now let’s prepare the Managed Bean which we will use to manipulate the datatable, starting by creating a list that persons to fill the datatable.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package com.alibassam.blog;
 
import java.util.ArrayList;
import java.util.List;
 
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
 
 
@ManagedBean(name="dataTableBean")
@ViewScoped
public class DataTableBean {
 
	private List<Person> personsList;
 
	public List<Person> getPersonsList() {
		return personsList;
	}
 
 
	public DataTableBean () {
		personsList = new ArrayList<Person>();
		personsList.add(new Person(1, "Jack", "jack@email.com"));
		personsList.add(new Person(2, "John", "john@email.com"));
		personsList.add(new Person(3, "David", "david@email.com"));
		personsList.add(new Person(4, "Tom", "tom@email.com"));
	}
}

For the page, I will add the datatable component and specify the value and var attributes so we can display the list inside the datatable.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:ui="http://java.sun.com/jsf/facelets" 
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:f="http://java.sun.com/jsf/core"
	xmlns:ace="http://www.icefaces.org/icefaces/components">
 
 
<h:head>
	<title>ICEfaces ACE DataTable Tutorial</title>
</h:head>
 
 
<h:body>
	<h:form>
		<ace:dataTable value="#{dataTableBean.personsList}" var="person">
			<ace:column headerText="ID">
				<h:outputText value="#{person.id}"></h:outputText>
			</ace:column>
			<ace:column headerText="Name">
				<h:outputText value="#{person.name}"></h:outputText>
			</ace:column>
			<ace:column headerText="Email">
				<h:outputText value="#{person.email}"></h:outputText>
			</ace:column>
		</ace:dataTable>
	</h:form>
</h:body>
</html>

And now our datatable is ready for experiments.

1- Single Row Select

DataTableRowSelect

One of the most required features is the ability to select a row and obtain the data that was selected, and this is very easy to do. First we need to bind the rowSelectListener attribute to a method, and set selectionMode to single.

1
2
3
4
5
6
7
8
9
10
11
12
13
<ace:dataTable value="#{dataTableBean.personsList}" var="person"
			rowSelectListener="#{dataTableBean.rowSelectListener}"
			selectionMode="single">
	<ace:column headerText="ID">
	        <h:outputText value="#{person.id}"></h:outputText>
	</ace:column>
	<ace:column headerText="Name">
		<h:outputText value="#{person.name}"></h:outputText>
	</ace:column>
	<ace:column headerText="Email">
		<h:outputText value="#{person.email}"></h:outputText>
	</ace:column>
</ace:dataTable>

And then we create the method which will handle this event, and it should receive an org.icefaces.ace.event.SelectEvent argument.

1
2
3
public void rowSelectListener(SelectEvent event) {
	Person p = (Person) event.getObject();
}

We retrieved the selected Person from the event.

2- Multiple Row Select

In case we would want to select multiple rows, we need to change selectionMode to multiple.

1
2
3
4
5
6
7
8
9
10
11
12
13
<ace:dataTable value="#{dataTableBean.personsList}" var="person"
		rowSelectListener="#{dataTableBean.rowSelectListener}" 
		selectionMode="multiple">
	<ace:column headerText="ID">
		<h:outputText value="#{person.id}"></h:outputText>
	</ace:column>
	<ace:column headerText="Name">
		<h:outputText value="#{person.name}"></h:outputText>
	</ace:column>
	<ace:column headerText="Email" >
		<h:outputText value="#{person.email}"></h:outputText>
	</ace:column>
</ace:dataTable>

And back in the listener method, we can retrieve a java.util.List of Person object by accessing the org.icefaces.ace.component.datatable.DataTable object.

1
2
3
4
public void rowSelectListener(SelectEvent event) {
	DataTable table = (DataTable) event.getComponent();
	List<Person> selectedPersonsList = (List<Person>) table.getStateMap().getSelected();
}

In case we do not want to rely on the rowSelectListener, but we want to retrieve the list of selected rows when we click later on another button, we can do so by binding the stateMap attribute to an org.icefaces.ace.model.table.RowStateMap object.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<ace:dataTable value="#{dataTableBean.personsList}" var="person"
	stateMap="#{dataTableBean.stateMap}" selectionMode="multiple">
	<ace:column headerText="ID">
		<h:outputText value="#{person.id}"></h:outputText>
	</ace:column>
	<ace:column headerText="Name">
		<h:outputText value="#{person.name}"></h:outputText>
	</ace:column>
	<ace:column headerText="Email">
		<h:outputText value="#{person.email}"></h:outputText>
	</ace:column>
</ace:dataTable>
 
<h:commandButton value="Get Rows" actionListener="#{dataTableBean.actionListener}"/>

And for the Java part:

1
2
3
4
5
6
7
8
9
10
11
12
13
private RowStateMap stateMap;
 
public RowStateMap getStateMap() {
	return stateMap;
}
 
public void setStateMap(RowStateMap stateMap) {
	this.stateMap = stateMap;
}
 
public void actionListener(ActionEvent event) {
	List<Person> selectedPersonsList = (List<Person>) stateMap.getSelected();
}

3- Cell Select

DataTableCellSelect

Either we wanted to select a single cell or multiple cells, this can be easily defined in the selectionMode attribute. The correspondent values are singlecell and multiplecell.

To retrieve the selected cell(s), we bind an Array of org.icefaces.ace.model.table.CellSelections to the selectedCells attribute.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<ace:dataTable value="#{dataTableBean.personsList}" var="person"
	selectedCells="#{dataTableBean.selectedCells}" selectionMode="singlecell">
	<ace:column headerText="ID"  >
		<h:outputText value="#{person.id}"></h:outputText>
	</ace:column>
	<ace:column headerText="Name" selectBy="#{person.name}">
		<h:outputText value="#{person.name}"></h:outputText>
	</ace:column>
	<ace:column headerText="Email" selectBy="#{person.email}">
		<h:outputText value="#{person.email}"></h:outputText>
	</ace:column>
</ace:dataTable>
 
<h:commandButton value="Get Cells" actionListener="#{dataTableBean.actionListener}"/>

You could notice that I defined the selectBy attribute for the , this attribute determines what kind of data I will be able to retrieve when I select a cell, so in the example above, if I click on the second cell of any row, I will receive the name, and if I select the third cell of any row, I will receive the email.

Back to the Managed Bean:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
private CellSelections[] selectedCells;
 
public CellSelections[] getSelectedCells() {
	return selectedCells;
}
 
public void setSelectedCells(CellSelections[] selectedCells) {
	this.selectedCells = selectedCells;
}
 
public void actionListener(ActionEvent event) {
        // Loop through all Selected Cells
	for(CellSelections cell : selectedCells) {
                // Retrieve a List of String which contains
                // the data provided by the cell
		List<String> data = cell.getSelectedFieldValues();
                // Retrieve the Object of the Row, 
                // in our case it's a Person object
                Person person = (Person) cell.getRowObject();
	}
}

4- Cell Select with AJAX

A more modern way to fetch the selected cell(s) is to rely on AJAX events. This can be done using the ajax tag, we define the event that we expect to occur, the execute space-separated list of client IDs to be executed, the render space-separated list of client IDs to be rendered and updated, and finally a listener method which does our custom work in Java. Take note that when relying on AJAX events, it is important to define client side IDs, not just for the component that will be affected, but also to its parent.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<h:form id="form">
	<ace:dataTable value="#{dataTableBean.personsList}" var="person"
			selectedCells="#{dataTableBean.selectedCells}"
			selectionMode="multiplecell" id="table">
		<ace:ajax event="select" render="@this form:result" execute="@this" 
                        listener="#{dataTableBean.ajaxUpdate}"/>
		<ace:ajax event="deselect" render="@this form:result" execute="@this" 
                        listener="#{dataTableBean.ajaxUpdate}"/>
		<ace:column headerText="ID" selectBy="#{person.id}">
			<h:outputText value="#{person.id}"></h:outputText>
		</ace:column>
		<ace:column headerText="Name" selectBy="#{person.name}">
			<h:outputText value="#{person.name}"></h:outputText>
		</ace:column>
		<ace:column headerText="Email" selectBy="#{person.email}">
			<h:outputText value="#{person.email}"></h:outputText>
		</ace:column>
	</ace:dataTable>
 
	<h:panelGroup  id="result" layout="block" style="width: 400px;">
		<h:outputText value="Selected Cells:" /><br />
		<ui:repeat value="#{dataTableBean.cellsList}"
			var="cell">
			<h:outputText value="#{cell}" />
			<br />
		</ui:repeat>
	</h:panelGroup>
</h:form>

First we have defined an id for the form, and just like the previous example, the selected cells will be available in the Array of CellsSelection.

The first ajax tag basically says that whenever a select event occurs, execute the table (@this), invoke the listener method, and then render and update both the table and the result container. The second is exactly the same, but it will fire when the event is deselect.

The panelGroup with the id equals to result will be updated on any of the above events, which means that the repeat component will fetch the new updated list of values after each event.

And now just a little bit of Java to populate a List of String (or any other object you prefer, you can still grab the whole Person object), extracted from the Array of CellsSelection.

1
2
3
4
5
6
7
8
9
public void ajaxUpdate(AjaxBehaviorEvent event) {
	cellsList = new ArrayList<String>();
	for(CellSelections cell : selectedCells) {
		// Retrieve the Selected Value
		cellsList.add(cell.getSelectedFieldValues().toString());
		// We can actually retrieve the Selected Row (Person Object)
		// cell.getRowObject();
	}
}

We should have the following results:

DataTableCellSelectAjax

Take note that AJAX events can also be used for row select.

5- Pagination

Now who doesn’t love to get a fully working out of the box pagination? All we need to do is to set the value of the paginator attribute to true.

1
2
3
4
5
6
7
8
9
10
11
12
<ace:dataTable value="#{dataTableBean.personsList}" var="person"
	paginator="true" rows="2">
	<ace:column headerText="ID" >
		<h:outputText value="#{person.id}"></h:outputText>
	</ace:column>
	<ace:column headerText="Name" >
		<h:outputText value="#{person.name}"></h:outputText>
	</ace:column>
	<ace:column headerText="Email" >
		<h:outputText value="#{person.email}"></h:outputText>
	</ace:column>
</ace:dataTable>

And here it goes:

DatatablePaginator

Note that you need to set a value for the rows attribute, or the whole set of data will be displayed, which will make the paginator useless.

Some Cool Attributes

  • pageCount: determines the number of pages to be displayed in the paginator
  • page: you might want to link this attribute to Java, it allows you to switch to a page of your choice, useful for paginator reset.
  • paginatorAlwaysVisible: set this to “false”, and the paginator will disappear when it’s not needed (when there’s no more than one single page to be displayed)
  • paginatorPosition: default value is “both”, you can change that to either “top” or “bottom”
  • emptyMessage: use this to define a sentence which will be displayed when no data is available
  • paginatorTemplate: this is a really cool feature, the default template for a paginator (as you can see above) is: “{FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink}”, you can change that to something like: “{FirstPageLink} | {PreviousPageLink} | {PageLinks} | {NextPageLink} | {LastPageLink}” and then you will have this:

DataTablePaginatorTemplate

6- Sorting

Sorting is enabled individually on columns, you choose which column is allowed to be sorted by specifying the sortBy attribute, giving it the value on which sorting occurs, basically you would give it the same value displayed in the column cells.

1
2
3
4
5
6
7
8
9
10
11
<ace:dataTable value="#{dataTableBean.personsList}" var="person">
	<ace:column headerText="ID" sortBy="#{person.id}">
		<h:outputText value="#{person.id}"></h:outputText>
	</ace:column>
	<ace:column headerText="Name" sortBy="#{person.name}">
		<h:outputText value="#{person.name}"></h:outputText>
	</ace:column>
	<ace:column headerText="Email" sortBy="#{person.email}">
		<h:outputText value="#{person.email}"></h:outputText>
	</ace:column>
</ace:dataTable>

DataTableSort

The “1” number displayed in the column header represents the order of sorting, by default, multiple sorting is allowed, and can be done by clicking on different column headers while tapping the CTRL button, as you can see in the following:

DataTableSortMultiple

To disable multiple sorting, set the singleSort attribute to false.

To be continued in part 2…

Categories: JavaServer Faces Tags: Tags: , , ,

3 Replies to “Exploring ICEfaces ACE Datatable Component (1)”

  1. It’s a great article, Im looking forward to reading the second part of ace datatable.

    Thanks so much man!!

Leave a Reply

%d bloggers like this: