Skip to content

DataTable 2.x

RomanPerin edited this page Aug 28, 2014 · 22 revisions

TOCSTART

TOCEND

The DataTable component is used to display data in a tabular format and effectively manipulate it. It supports the features of the JSF HtmlDataTable component and extends the standard functionality with features as sorting, row selection (both multiple and single), cell selection, pagination, filtering, keyboard navigation, and dynamic data loading (using Ajax.) Plus, the DataTable component provides special support for handling large datasets with minimal overhead.


Online Demo

Key Features

Interactive Data Navigation

DataTable lets the user interactively query the data in virtually any way to meet a wide variety of usage scenarios.

Representing Complex Data Structures

These features allow to represent and provide convenient user interface for displaying lists of complex entity types, for example where fields are grouped into complex sub-types, or the number of fields (aka columns) is dynamic.

Efficient Data Handling

The following features allow optimizing the network traffic and memory.

Flexible Data Visualization

There is a number of ways for customizing how a "raw" data is displayed to address various design requirements.

Specifying the Content

To add the DataTable component to a page, use the <o:dataTable> tag. The content for the DataTable component is specified in the same way as for the standard JSF HtmlDataTable. The two basic things you need to do are to specify the list of rows, using the value attribute of the DataTable component, and the list of columns, with child column tags of the <o:dataTable> tag.

The DataTable component supports several column types: <o:column>, <o:checkboxColumn> and <o:selectionColumn> (for more information, see the section Specifying Columns below). In addition you can specify dynamic number of columns using the <o:columns> tag. Child components of the column tag define the contents of the column cells based on the corresponding row's data. When the DataTable component is being rendered, it repeatedly makes current the row data for each row and renders all cells for that row based on the list of columns.

Note that the same child components of a column are rendered in every cell of that column. So in order for these components to display different data for each respective row, you should use a request-scope variable referring to the current row's data (see section Request-Scope Variables).

Specifying Rows

The list of rows is specified using the value attribute of the <o:dataTable> tag. This attribute should be configured as a value-binding expression that refers to either of these data types: array, collection, JDBC ResultSet, JSTL ResultSet. Note that unlike the standard HtmlDataTable component, you are allowed to specify not only a java.util.List implementation, but any implementation of the java.util.Collection interface as a value of the value attribute. Each object in the referenced list is called "row data" and will be used to display one row of data. Note that all row data objects in the collection that the value attribute retrieves should be not-null. If the value attribute references any other type of object, the DataTable component will display one row of data based on that object.

Request-Scope Variables

When specifying child components of the DataTable or table's columns, you can use request-scope variables that reference the current row's parameters. There are two such variables. To use any of them, you should declare its name in the corresponding attribute of the <o:dataTable> tag:

  • var (required) - The name of a request-scope variable under which the current row data is available.
  • rowIndexVar (optional) - The name of a request-scope variable under which the current row index is available when declaring components inside columns or specifying the condition for the <o:row>, <o:cell> tags. Note that if pagination is used on the table, this variable will refer to the "absolute" row index, which means that numbering won't restart starting from each page but will be relative to the first row of the first page.

In addition there are two more variables provided to configure an individual cell by the condition. These variables are available when specifying the condition for the <o:cell> and <o:cellStyle> tags, and when choosing the selectable cells in the Cell Selection feature:

  • columnIndexVar (optional) - The name of a request-scope variable under which the column index is available.
  • columnIdVar (optional) - The name of a request-scope variable under which the column identifier is available.

Server-side event handlers can be aware of the row where an event occurs by checking the current row data or row index that can be retrieved with these request-scope variables. If the value is evaluated by a backing bean method, you can use the org.openfaces.util.Faces.var(String varName) method to retrieve a variable by its name.

Model Row Objects Requirements

In cases when the DataTable has any editable or command components in its rows, or when it contains the selection or checkbox column features, additional requirements are imposed on specifying the table data source. If these features are not used in your table then you can ignore the requirements mentioned below.

More formally, this is required when the table is not a so called display-only table. The table can be considered as a display-only one when there are no components that implement EditableValueHolder, ActionSource classes (such as <h:inputText> or <h:commandButton> components), and the check-box column and selection features are absent.

One of the following requirements should be met for such tables:

  • The rowKey attribute should be specified. This attribute retrieves a row key that must uniquely identify an appropriate row and satisfy should be serializable and correctly implement the equals and hashCode methods. Note that rowKey attribute binding should not return a null value.
  • Alternatively, all row data instances provided by the value attribute should be serializable and correctly implement the equals and hashCode methods.

These requirements are needed to properly handle the cases when the underlying data that is provided to the DataTable component (through its value attribute) changes between the page rendering time and the time that it gets submitted to the server. See also the Concurrent Data Modifications section below.

Using the rowKey attribute is preferred. In practice, if you are displaying objects read from the database, and their primary key field is of a primitive or string type, the rowKey attribute should usually just refer to the primary key field of the displayed objects, which meets all of the required criteria.

<o:dataTable var="product"
             value="#{ProductsList.products}"
             rowKey="#{product.id}">
  ...
</o:dataTable>
Concurrent Data Modifications

The DataTable component allows you to insert any editable components in its cells, such as <h:inputText>, <h:selectManyCheckbox>, selectManyCheckbox, etc. However, in this case, a problem with concurrent data modification may arise. For example, while one user is editing some rows, the other can delete one of them. The DataTable component provides a mechanism to resolve such kind of problems. If row data meets the data source requirements, edited data will be saved properly, even if the row order has changed.

Optionally, you can specify the rowDataByKey attribute. In this case, the data of edited rows is saved into the backing bean, even if this bean is already unavailable through the data source. A typical example is simultaneous editing of the same row(s) by different users. If the rowDataByKey attribute is not specified, deleted rows will be removed and edited data will be ignored.

Specifying Columns

The list of DataTable's columns is specified using the <o:column> child tags. Columns are used to split each row provided by the value attribute into cells. Child components of the <o:column> tag are used to render each cell of the current row. When the DataTable component is being rendered, it repeatedly makes current each row taken from value and renders all cells for that row based on the list of columns. Each table column defines the content of its header, footer, and body cells. The content for the body cells is specified using row request-scope variables (for more details about them, see the section Request-Scope Variables).

In addition to the <o:column>, the DataTable component supports also two types of columns:

  • <o:checkboxColumn> - This tag renreds a column of check boxes whose values are not stored in the row data object (for more detail see section Using a Checkbox Column).
  • <o:selectionColumn> - This column shows check boxes for multiple row selection or radio buttons for single row selection. The selection column is an alternative way for the user to change selection and see which row(s) is selected.

The DataTable also provides an ability to define dynamic number of columns. For more details about this feature please see section Specifying Dynamic Columns.

Column Facets

A table column has the "header", "subHeader" and "footer" facets which you can use to specify the table header, sub-header and footer respectively. The "header" facet is usually used for displaying the column name, the "subHeader" facet usually contains the column filter component and the "footer" facet is normally used for displaying the column's total value, though naturally these are not the requirements and the purpose can be different depending on application design.

The example below shows a two-column DataTable component with column headers. The first column displays product images and the second their names. The var attribute defines the "product" variable which is used by the columns' child components to retrieve data for the appropriate row.

<o:dataTable var="product" value="#{ProductList.products}">
  <o:column>
    <f:facet name="header">
      <h:outputText value="Image" />
    </f:facet>
    <h:graphicImage url="images/#{product.imageFileName}" />
  </o:column>
  <o:column>
    <f:facet name="header">
      <h:outputText value="Name" />
    </f:facet>
    <h:outputText value="#{product.name}" />
  </o:column>
</o:dataTable>
Specifying Header and Footer

Some components bound to a DataTable such as a CompositeFilter component or column visibility popup menu require displaying column names. In cases when the "header" facet contains a UIInput component such as <h:outputText> the column name can be extracted from the facet's content automatically (the value of the first UIInput is taken), though it is not always possible, for example when an image is displayed in column's header or when another text should be used as a column's name in the bound components. To address these scenarios, each of the column tags allow specifying the "header" attribute where you can specify a string value to be used as column name.

Another purpose of the "header" attribute and that's where another related attribute can also be useful is a replacement for the "header" and "footer" facet respectively. If there's no "header" facet and the value specified in the "header" attribute is
displayed in the column's header. The same is applicable for the replacing the footer value. If both attribute and facet is specified, then the facet's content is used for displaying the header/footer cell.

Specifying Dynamic Columns

In addition to column types listed in section Specifying Columns the OpenFaces DataTable provides an ability to specify dynamic list of columns. This can be done by adding the <o:columns> child tag to the <o:dataTable> tag. This tag can be used in any place where the ordinary <o:column> tag can be used.

The list of the dynamic columns is specified using the value attribute of the <o:columns> tag. This attribute should be specified as a value-binding expression that refers to an array or a collection of objects that serve as column data objects. The <o:columns> tag results in adding one column per each object found in this collection. The column data objects must be serializable and correctly implement equals and hashCode methods. You should make sure to provide objects that identify their respective columns in any way that should be sufficient for distinguishing between columns when they are rendered or their properties are calculated. See below for the places where column data objects are used. Please note the var request-scope variable of the DataTable is not available when you specify the value attribute of the <o:columns> tag.

Most of the attributes of <o:columns> tag are analogous to their counterparts in the <o:column> tag but they have one valuable difference – an ability for the attributes to be specified as value binding expressions that allow specifying column attributes on a per-column basis. You need to use the column data request-scope variable in value binding expressions in order to specify column-specific attribute values. The name of this request-scope variable should be specified in the var attribute of the <o:columns> tag. In some cases it is more convenient to use column index instead of column data value when specifying values that should depend upon the column in which they are used. For this purpose, you can use an additional column index variable, whose name can be specified in the indexVar attribute of <o:columns> tag. This variable and the column data variable can be used to identify the currently displayed column.

Similarly to the ordinary columns, the content displayed in dynamic columns is specified by the set of child components located in the <o:columns> tag. The difference from the ordinary columns here is that with <o:column> tag, you have to use only the variable(s) identifying the currently displayed row, and in case of <o:columns> tag, you have to use variable(s) that identify the currently displayed column as well. The combination of these row- and column- identifying variables gives you the information on which cell is currently being displayed.

The <o:columns> tag does not have the id or rendered attributes. However, you can specify the identifier and a flag that indicates whether or not the column is visible for each dynamic column using the columnId and columnRendered attributes of the <o:columns> tag, respectively. These attributes should be specified as value-binding expressions that refer to identifier or a flag indicating whether column is visible for each dynamic column. You can use a column data variable specified in the var attribute in the expression for these attributes. Please note that column identifiers evaluated for columns inside the <o:columns> tag are used in the same way as id attributes of ordinary <o:column> tags, so the identifiers evaluated using this expression should be unique in bounds of the containing DataTable.

The following example demonstrates the usage of the <o:columns> tag:

<o:dataTable value="#{TableBean.rowDatas}"
             var="row">
<o:columns value="#{TableBean.columnDatas}"
           var="col"
           indexVar="colIndex"
           columnId="dynamicCol#{colIndex}"
           columnRendered="#{TableBean.columnRendered}">
    <f:facet name="header">
        <h:outputText value="#{col.name}"/>
    </f:facet>
    <h:outputText value="#{row.columnValues[colIndex]}"/>
</o:columns>
</o:dataTable>

Similarly to an ordinary <o:column> tag, the <o:columns> tag supports sorting, filtering, style customization and columns-specific events.

Combining Columns into Groups

It is possible to combine columns into groups to reflect their logical connections. This can be done by enclosing several column tags into the <o:columnGroup> tag. This tag has the set of features similar to that of ordinary columns:

  • Specifying the "header" and "footer" facets for a group of columns. This will show an additional header (or footer) that spans across all of the inner columns.
  • Specifying style for a group of columns as described in the Column Styles section.
  • Specifying events for a group of columns as described in the Specifying User Events section.

Here's a simple example of using column groups:

<o:dataTable value="#{TableBean.products}" var="product">
<o:column>
    <f:facet name="header">
        <h:outputText value="Name"/>
    </f:facet>
    <h:outputText value="#{product.name}"/>
</o:column>
<o:columnGroup>
    <f:facet name="header">
        <h:outputText value="Price"/>
    </f:facet>
    <o:column>
        <f:facet name="header">
            <h:outputText value="Retail"/>
        </f:facet>
        <h:outputText value="#{product.retailPrice}"/>
    </o:column>
    <o:column>
        <f:facet name="header">
            <h:outputText value="Wholesale"/>
        </f:facet>
        <h:outputText value="#{product.wholesalePrice}"/>
    </o:column>
</o:columnGroup>
<o:columnGroup>
    <f:facet name="header">
        <h:outputText value="Features"/>
    </f:facet>
    <o:column>
        <f:facet name="header">
            <h:outputText value="Feature 1"/>
        </f:facet>
        <h:outputText value="#{product.features.feature1}"/>
    </o:column>
    <o:column>
        <f:facet name="header">
            <h:outputText value="Feature 2"/>
        </f:facet>
        <h:outputText value="#{product.features.feature2}"/>
    </o:column>
</o:columnGroup>
</o:dataTable>

Note that there are both the columns that are enclosed into <o:columnGroup> tag and the column that is not part of any group. It is also possible to create nested column groups, thus establishing an arbitrary hierarchy of columns.

It is possible to emphasize separation of columns into groups with a feature of customizing gridlines for different levels of columns (or groups). See the Column Group Separators section for details.

Changing Column Order

You can change the order of columns in the DataTable component by using the columnsOrder attribute. It should be declared as a value-binding expression, and the bound value should be a list containing column IDs for each column in the order you want them to be displayed. If the columnsOrder attribute is not specified, all the columns are rendered in the order they are defined. Otherwise, only the columns whose IDs are included in this list are rendered.

The following example shows columns that are explicitly ordered using the columnsOrder attribute.

<o:dataTable var="product"
             value="#{ProductsList.products}"
             columnsOrder="#{ProductsList.columnsOrder}">
  <o:column id = "imageColumn"> ... </o:column>
  <o:column id = "nameColumn"> ... </o:column>
  <o:column id = "priceColumn"> ... </o:column>
  <o:column id = "quantityColumn"> ... </o:column>
</o:dataTable>

Drag & Drop Column Reordering

It is possible to let the user reorder columns interactively with drag & drop by adding the <o:columnReordering> tag into the <o:dataTable> tag. When this feature is turned on, the user can drag the column by its header and drop it into the appropriate place in-between columns. The current drop target is highlighted for user's convenience. In case of the tables with horizontal scrolling enabled (see the Content Scrolling section), the autoscroll areas will pop up on the header's left and/or right sides allowing the user to scroll the table while dragging the column.

The order of columns is read from and saved to the columnsOrder attribute of <o:dataTable> tag, so you can bind this attribute to your backing bean if you'd like to receive the column order changes. See the Changing Column Order section for the description of columnsOrder attribute.

Mere adding of the <o:columnReordering> tag will turn on the reordering behavior though you can also configure the attributes of this tag to adjust styles and appearance of various parts of UI that participate in the reordering process.

Dragging the column header creates a visual copy of the header cell that the user is dragging, and it's possible to apply an additional style to the dragged cell using the draggedCellStyle and draggedCellClass attributes. By default, the dragged cell is displayed as semitransparent and the transparency level can be configured using the draggedCellTransparency attribute, where 0.0 corresponds to the fully-opaque display, and 1.0 corresponds to the fully-transparent display.

The appearance of drop target can be customized with the following attributes

Attribute Description
dropTargetStyle, dropTargetClass The CSS class applied to the drop target area. The usual attributes that should be configured for drop target style are the "background" and "width" CSS attributes.
dropTargetTopImageUrl, dropTargetBottomImageUrl Allow customizing images that are displayed above and below the drop target (the default images display the arrows).

Finally, the appearance of the auto-scroll areas that appear on the horizontally-scrollable tables can be configured with the following attributes:

Attribute Description
autoScrollAreaStyle, autoScrollAreaClass The style for the autoscroll areas. You will usually want to configure the background, width and possibly border CSS attributes.
autoScrollAreaTransparency The transparency level for the autoscroll areas. The default value is 0.5, which means a semitransparent display. The value of 0.0 corresponds to the fully opaque display
autoScrollLeftImageUrl, autoScrollRightImageUrl The images that are displayed in the left and right autoscrolling areas respectively

Here's an example of turning on the column reordering feature for DataTable with customizing the drop target color and binding the column order to a backing bean:

<o:dataTable ...
    columnsOrder="#{ProductsList.columnsOrder}">

<o:columnReordering dropTargetStyle="background: red"/> ... </o:dataTable>

Column Resizing

It is possible to let the user resize columns by adding the <o:columnResizing> tag as a child of <o:dataTable> tag. When column resizing is turned on, the user can drag the column header separators to resize columns. The total table width is not affected by the process of resizing columns. It should also be noted that if table width doesn't have a fixed width specification, for example when it is declared to have 100% width, then table layout behavior is slightly changed when column resizing is turned on. The table is loaded with its width properly calculated using the specified relative width, though after the page is loaded the table's width is fixed and is not recalculated.

The <o:columnResizing> tag can be added without specifying any attributes, though there are some optional configuration attributes. The resizeHandleWidth attribute specifies the size of the "dragging area" near the column header separator. This area can be wider than the separator itself to make it easier for the user to locate the draggable area. The minColWidth attribute can be used to specify the minimum width that a column can take after resizing. Both of these attributes can be specified in any CSS units except percent.

Here's an example of adding the column resizing capability to a table:

<o:dataTable var="product"
             value="#{ProductsList.products}"
             width="100%">
  <o:columnResizing resizeHandleWidth="10px" minColWidth="50px"/>

<o:column id = "imageColumn"> ... </o:column> ... </o:dataTable>

The table's width attribute must be specified when using the column resizing feature.

There are also two per-column attributes that are applicable only when a table has the column resizing feature. It is possible to make certain column non-resizeable by assigning "false" to the column's resizeable attribute. There is also the possibility to specify the minimum resizing width on a per-column basis. Specifying the column's minResizingWidth attribute overrides the default minimum width value defined by the <o:columnResizing> tag.

Column width changes made by the user can be persisted between different visits of the appropriate page using the <o:columnResizing> tag's resizingState attribute. This attribute can be bound to a backing bean property having the org.openfaces.component.table.ColumnResizingState type. This property will be written to save the current column widths when columns are resized, and will be read when the table is rendered next time. The additional <o:autoSaveState> attribute defines when the resizing state is sent to the server (and thus when the resizingState attribute binding is updated). By default it is set to true, which means that column widths are saved on-the-fly with Ajax requests after any column is resized. Setting this attribute to false will turn off the column width saving Ajax requests and will make the column widths data to be sent to the server along with the nearest form submission (or Ajax DataTable component submission).

Displaying Column Menus

It is possible to add the column menu to allow performing the standard column operations such as sorting, showing and hiding columns, or to provide custom column-specific operations. The column menu feature is turned on by specifying the "columnMenu" facet. Specifying this facet makes a drop-down button to appear in the column's header when the user hovers over the header, and pressing this button shows the menu. You can either specify the standard column menu with the <o:columnMenu> tag in this facet, or a custom menu with the <o:popupMenu> facet. By default, this menu will be available through the header of all columns except selection and check-box columns. You can turn off the displaying of column menu for a certain column(s), or turn it on for selection/check-box columns using the menuAllowed boolean attribute on <o:column> or other column tags.

It is possible to customize the content and appearance of the standard menu by customizing the <o:columnMenu> tag's attributes and child tags. Adding any menu item tags inside of the <o:columnMenu> tag will replace the standard structure with the custom menu item hierarchy. This provides the full flexibility for reordering, restyling or removing the standard items and adding the custom ones. The standard menu items can be specified with the following tags:

  • sortAscendingMenuItem tag as the name says allows sorting the column in an ascending order;
  • sortDescendingMenuItem tag allows sorting the column in an descending order;
  • hideColumnMenuItem allows hiding the column;
  • resetSortingMenuItem allows user to switch the column to the initial unsorted state (will not be displayed if unsortedStateAllowed attribute is false);
  • columnVisibilityMenu tag can be embedded into the ordinary <o:menuItem> tag to display the column visibility customization sub-menu, where all columns are listed with check-boxes against each of them.

Additionally you can place a <o:menuSeparator> tag to insert separators and a <o:menuItem> tag to add custom menu items. Similarly, you can avoid displaying the standard menu at all, and specify the popupMenu tag as the content of the "columnMenu" facet for an entirely custom column menu.

Here's a simple example of displaying the customized menu, with two additional "Select Column" and "Unselect Column" menu items:

  <o:dataTable id="table" ...>
    ...
    <f:facet name="columnMenu">
      <o:columnMenu indentStyle="color: yellow">
        <o:sortAscendingMenuItem/>
        <o:sortDescendingMenuItem/>
        <o:hideColumnMenuItem/>
        <o:menuSeparator/>
        <o:menuItem value="Columns">
          <o:columnVisibilityMenu/>
        </o:menuItem>
        <o:menuSeparator/>
        <o:menuItem value="Select Column" onclick="selectColumn(O$('form:table').getCurrentColumn().index);"/>
        <o:menuItem value="Unselect Column" onclick="unselectColumn(O$('form:table').getCurrentColumn().index);"/>
      </o:columnMenu>
    </f:facet>
    ...
  </o:dataTable>

Note that in order to implement functionality for custom menu items, you can use the getCurrentColumn() client-side method to detect the column for which the popup menu is invoked. This function returns the client-side column object where only one field is currently available: index. This is a zero-based index of a column in a list of currently rendered columns.

The standard menu and menu item tags can be customized with the same attributes as the usual popupMenu and <o:menuItem> tags (except some obvious non-applicable attributes such as subMenuImageUrl for sortAscendingMenuItem since it can't have a sub-menu, etc).

The column visibility sub-menu (displayed as part of the standard menu or specified in a customized menu with the columnVisibilityMenu) has a two-fold way of detecting the column names for displaying in the menu. First, it checks the optional column's header attribute (which exists in all column tags), and if this attribute is not defined, then it inspects the content of the "header" facet of the appropriate column and takes the value of the first UIOutput component found in that facet (such as <h:outputText>).

The appearance of the drop-down button that appears in the column header and invokes the column's popup menu can be customized with the "columnMenuButton" facet. This facet must contain the <o:captionButton> tag where you can customize all appearance properties for the menu invoker button.

Note that the column visibility changes made with the column menu are reflected into the columnsOrder attribute of the <o:dataTable> tag, so you can bind that attribute to be able to save column visibility between different page visits.

Table Headers and Footers

The DataTable component has the header and footer areas that are displayed as the first and last rows of the table and span the width of the component. The content of these areas can be specified with the "header" and "footer" facets of the <o:dataTable> tag. The styles for these areas can also be customized (see the section Section Styles).

The DataTable component also has two special areas located right before and after the table content. The content of these areas can be specified with the "above" and "below" facets of the <o:dataTable> tag.

Note that the content of all the facets described above is refreshed after Ajax requests that reload the entire DataTable content (as in the case of filtering and sorting updates).

<o:dataTable var="person" value="#{PeopleList.person}"
             style="border:1px dotted gray;">
  ...
  <f:facet name="above">
    <h:outputText value="'Above' facet goes before the DataTable"/>
  </f:facet>
  <f:facet name="header">
    <h:outputText value="'Header' facet goes as the first row of the DataTable"/>
  </f:facet>
  <f:facet name="footer">
    <h:outputText value="'Footer' facet goes as the last row of the DataTable"/>
  </f:facet>
  <f:facet name="below">
    <h:outputText value="'Below' facet goes after the DataTable"/>
  </f:facet>
</o:dataTable>

In the following figure, you can see all the facets defined in the previous example:

Displaying a Message for Empty Data

If there are no records to display in the cells of the DataTable component, a default message "No records" is displayed. You can turn it off by setting the noDataMessageAllowed attribute to "false" (by default, it is "true"). You can specify your own message by using the "noDataMessage" facet. To apply styles for the row displaying this message, use the noDataRowStyle and noDataRowClass attributes.

If there is data in the data source but no records satisfy the current filtering settings (see the section Filtering below), then a different message "No records satisfying the filtering criteria" is displayed. You can change this message text by specifying the "noFilterDataMessage" facet.

The example below shows a customized message for empty data.

<o:dataTable var="product"
             value="#{ProductList.products}"
             noDataRowStyle="color:red; font-weight:bold; font-size:20pt">
  <f:facet name="noDataMessage">
    <h:outputText value="There is no data" />
  </f:facet>...
</o:dataTable>

Content Scrolling

It is possible to configure the DataTable component to scroll its content when all rows (and/or columns) cannot fit within the allotted area. This can be done simply by placing the <o:scrolling> inside of the <o:dataTable> tag. Adding this attribute makes the table to show the vertical scrollbar allowing the user to scroll through the table's data rows. Header and footer rows remain fixed independent of scrolling.

The <o:scrolling> tag makes it possible to turn on vertical or horizontal scrolling modes, or allow both scrolling directions at the same time. This can be done using the vertical and horizontal attributes of the <o:scrolling> tag, which are equal to true and false by default respectively. By default, assigning true to any of these attributes makes the appropriate scroll-bar to be displayed regardless of whether all data (rows or columns) entirely fits in the visible area or not. You can set the autoScrollbars attribute to true to show the scrollbars only when there's something to scroll, so that they are automatically hidden when the data entirely fits in the visible area.

If vertical scrolling is turned on, the table's height is fixed according to the CSS height attribute specified for the table (through table's style or styleClass attributes). It is also possible to modify this behavior by setting the minimizeHeight attribute of <o:scrolling> tag to true. Setting this attribute will make the table reduce its height by removing the empty space that remains when there's little rows and no scrolling is required.

It is possible to exclude one or more columns from horizontal scrolling and fix them on the table's left or right side by specifying the fixed attribute of the appropriate column(s) or column group(s). Note that only the first (and/or last) column(s) are allowed to be fixed, which means that you can't declare the fixed attribute for a column that resides in the middle of column list and is surrounded by non-fixed columns.

You can also disable vertical scrolling by assigning false to the vertical attribute, so When the horizontal attribute is set to true, y

The following example outlines the declaration of a table with both horizontal and vertical scrolling having its two first columns fixed:

<o:dataTable ...>
  <o:scrolling horizontal="true"/>

<o:checkboxColumn fixed="true" .../> <o:column fixed="true" .../> <o:column .../> <o:column .../> ... </o:dataTable>

The current scroll position can be detected and manipulated using the position property of the <o:scrolling> tag. This attribute should be bound to a variable of type java.awt.Point.

Sorting

The DataTable component provides sorting of displayed data based on the value of one of its columns. The user can change a sorting column and sort order by clicking on the column header.

Data can be sorted only by "sorting-aware" columns. To make a column sortable, you should specify the sortingExpression attribute and optionally, the sortingComparator attribute for this column. The sortingExpression attribute defines the row's value that will be used during sorting. It should be declared as a value-binding expression. The sortingComparator attribute defines the comparator that is used to compare the values provided by the sortingExpression attribute. This attribute should be specified as a value-binding expression and should reference the object that implements the java.util.Comparator interface. If the sortingComparator attribute is not defined, sortingExpression should evaluate to either a primitive type or an object that implements the java.lang.Comparable interface, for example String. To perform case-insensitive comparison of String values, the sortingComparator attribute provides a special "caseInsensitiveText" value.

In the following example, products in the table are sorted by name and price:

<o:dataTable var="product"
             value="#{ProductsList.products}">
  <o:column id="nameColumn" sortingExpression="#{product.name}"
            sortingComparator="caseInsensitiveText">
    <f:facet name="header">
      <h:outputText value="Name" />
    </f:facet>
    <h:outputText value="#{product.name}" />
  </o:column>
  <o:column id="priceColumn" sortingExpression="#{product.price}">
    <f:facet name="header">
      <h:outputText value="Price" />
    </f:facet>
    <h:outputText value="#{product.price}" />
  </o:column>
</o:dataTable>

Dynamic columns support sorting as well. Just like ordinary columns, dynamic columns can be made sortable by specifying the sortingEnabled attribute in <o:columns> tag. In this case, all dynamic columns become sortable. Though in some cases it's needed to make only a portion of columns sortable. This can be accomplished by declaring the sortingEnabled attribute of the <o:columns> tag. This attribute can be specified as a value-binding expression that refers to a boolean value indicating whether or not the current dynamic column is sortable based on the column data variable. You can also optionally specify the sortingComparator attribute. Note that the purpose and usage of sortingEnabled and sortingComparator attributes are the same as for the <o:column> tag, but they must be specified as a value-binding expressions that include a column data variable for specifying different sorting values and different sorting comparators for each column.

Here is an example of using the sorting feature in dynamic columns:

<o:dataTable value="#{TableBean.tableValue}"
             var="row">
<o:columns value="#{TableBean.dynamicColumns}"
           var="col"
           sortingExpression="#{row.dynamicColumns[col]}">
    <f:facet name="header">
        <h:outputText value="#{col}"/>
    </f:facet>
    <h:outputText value="#{row.dynamicColumns[col]}"/>
</o:columns>
</o:dataTable>

It is also possible to make the selection and check-box columns sortable. This can be done simply by setting their sortable attribute to "true". Here's an example:

<o:dataTable value="#{TableBean.tableValue}"
             var="row">
  <o:multipleRowSelection/>
  <o:selectionColumn sortable="true"/>
  <o:checkBoxColumn sortable="true"/>
  ...
</o:dataTable>

By default, rows displayed by the DataTable component are rendered in order of their specification without any sorting. You can customize sorting parameters using the sortColumnId and sortAscending attributes of the DataTable component. sortColumnId is a string attribute where you specify the ID of a column by which to sort the table. The sortAscending boolean attribute is used to specify the sort order. When sortAscending is "true", the table is sorted in ascending order, and vice versa.

By default, user can only switch between ascending and descending order of sorting, but it's also possible to allow user to switch table to unsorted state by click on the header or using column menu. This feature works in the following way: if table is sorted descending then next click on header will switch table to unsorted state, second one will sort table ascending. Set the boolean unsortedStateAllowed attribute to true for that.

The image that displays the sort direction is customizable. To change it, use the sortedAscendingImageUrl and sortedDescendingImageUrl attributes. Note that in order to have the column header text and sort image correctly aligned, the sort image should be approximately of the same height as characters in the header.

It is possible to highlight headers of sortable columns using the following styling attributes:

Description Style attributes Class attributes
Sortable column header sortableHeaderStyle sortableHeaderClass
Rollover style for sortable column header sortableHeaderRolloverStyle sortableHeaderRolloverClass

The styles different parts of a sorted column can be customized using the following attributes:

Parts of a sorted column Style attributes Class attributes
Entire column sortedColumnStyle sortedColumnClass
Column header sortedColumnHeaderStyle sortedColumnHeaderClass
Column body sortedColumnBodyStyle sortedColumnBodyClass
Column footer sortedColumnFooterStyle sortedColumnFooterClass

Pagination

By default, the DataTable component displays all the records provided by the value attribute. Sometimes, however, it may be necessary to limit the number of displayed rows for the sake of minimizing load time of a web page or saving the space the DataTable component occupies on the page. In this case, you can make use of the pagination feature.

When pagination is enabled, the data displayed by the DataTable component is broken down into equal portions of records called "pages". Only one page of records can be visible at a time. The user can navigate between the pages using special pagination components. In most cases, you will want to use the DataTablePaginator component (see the next section for more information). You can also use so-called custom data providing to optimize memory usage and performance when working with large dataset (for more information, see the section Handling Large Datasets).

To enable pagination in the DataTable component, you need to specify the pageSize attribute. This attribute defines the number of rows to be displayed on each DataTable page. If it is set to "0" (default), no pagination is provided. Also, you can optionally use the pageIndex attribute to specify the number of a currently displayed DataTable page.

By default, when pagination is enabled, the user can navigate to a specific DataTable page with the keyboard. The available keys and key combinations are listed below:

MS Windows/Linux Mac OS Action
Ctrl+Home + Go to the first page.
Ctrl+End + Go to the last page.
Page Up Go to the next page.
Page Down Go to the previous page.

You can turn the keyboard pagination feature off by setting the paginationKeyboardSupport boolean attribute to "false".

For advanced scenarios where page index should be detected for some particular row, e.g. if you need to switch to the page displaying some particular row, there's getPageIndexForRowKey method in the DataTable class.

Sometimes special behavior of pagination on table sorting is needed. Use paginationOnSorting attribute for this issues, by default the value of this attribute set to "firstPage", this value specify pagination switch to first page on sorting. Changing value to "samePage" specify pagination to stay on the same page during sorting.

You can set keepSelectionVisible boolean attribute to "true", this will specify pagination to keep selected row on the page during the sorting and filtering. If no row was selected the behavior of pagination will be ruled by the paginationOnSorting attribute.

DataTablePaginator Component

The DataTablePaginator component allows the user to navigate between the pages of the DataTable records. The component displays the total number of pages, number of a current page, a text field to type in the number of a page to go to, and a set of the Previous, Next, First and Last images for navigation.

The DataTablePaginator component is denoted by the <o:dataTablePaginator> tag. You should place it within the DataTable component, inside any of its facets. While you cannot place the DataTablePaginator outside of the DataTable component, you can use additionally provided "below" and "above" facets to insert the DataTablePaginator below or above the DataTable component.

Make sure to specify the id attribute for the the <o:dataTablePaginator> tag when placing it inside of "above" or "below" facets. See the Specifying the content of the "above" and "below" facets section for details.

If the default configuration of the DataTablePaginator component doesn't suffice for your needs, you can use additional attributes to customize its appearance. For example, setting the showPageCount boolean attribute to "false" (by default, it is "true") hides the total number of pages. The pageCountPreposition attribute lets you change the default text ("of") that separates the text field and total number of pages. The pageNumberPrefix attribute specifies the text that precedes the page number field.

By default, when all the records provided by the value attribute fit into one page, thus eliminating the need for the DataTablePaginator component, it is automatically hidden. You can change this behavior by setting the showIfOnePage attribute of the <o:dataTablePaginator> tag to "true".

It is possible to define styles for any part of the DataTablePaginator component with the following attributes:

Parts of DataTablePaginator Style attributes Class attributes
Entire component style styleClass
Text field for a page number pageNumberFieldStyle pageNumberFieldClass

The attributes for customizing the Previous, Next, First and Last images and tool tips are summarized in the table below:

Image Active image Disabled image Tool tip
First firstImageUrl firstDisabledImageUrl firstText
Previous previousImageUrl previousDisabledImageUrl previousText
Next nextImageUrl nextDisabledImageUrl nextText
Last lastImageUrl lastDisabledImageUrl lastText

You can specify whether to show disabled images by using a boolean showDisabledImages attribute. By befault, disabled images are visible.

The following example shows a pageable DataTable component displaying five rows of data for each page. The DataTablePaginator component is placed below the table.

<o:dataTable var="product"
             value="#{ProductsList.products}"
             pageSize="5">
  <f:facet name="below">
    <o:dataTablePaginator id="paginator"/>
  </f:facet>
  <o:column>
    <f:facet name="header">
      <h:outputText value="name" />
    </f:facet>
    <h:outputText value="#{product.name}" />
  </o:column>
</o:dataTable>

And here's the result of the DataTablePaginator configuration from the previous example:

Filtering

The DataTable component provides a powerful mechanism for interactive data filtering to make it easier for the users to browse data sets of any size and complexity. It is possible to:

  • define column data filters,
  • define filters that search data on a complex expression rather than a single-column expression,
  • use different types of filter components,
  • place filter components inside of the table or anywhere on the page,
  • customize all aspects of filtering behavior including search condition, case sensitivity, etc.,
  • customize all aspects of filters' visual appearance,
  • use the composite filter builder (the CompositeFilter component) as a universal filter component to allow the user build complex filter criteria interactively.
  • eaily add support for handling large data sets while utilizing all kinds of filters attached to the table.
Basic Usage

Even though it has a lot of features and customization possibilities, filtering is quite easy to incroporate into a table. The filtering functionality is defined using the filter tags, which when attached to a table, add a filtering interface and behavior according to the tag's customization. There are the following filter tags:

  • <o:inputTextFilter> – displays a text field that filters the data according to the expression specified in the filter.
  • <o:dropDownFieldFilter> – displays a drop-down field that filters the data according to the expression specified in the filter. The drop-down list contains all values that present in a table for the filter's expression or a custom list, so the user can type a value manually or select one from the list.
  • <o:comboBoxFilter> – displays a combobox that filters the data according to the expression specified in the filter. The combobox contains all values that present in a table for the filter's expression, or a custom list.
  • <o:compositeFilter> – displays a filter builder component where the user can compose a set of criteria based on table's columns. See the Using Composite Filter section below and the CompositeFilter component documentation.

These filters can be added in two ways:

  • Declared anywhere on a page and bound to the table using the filter's for attribute, which is used in the same way as the for attribute for the standard <h:outputLabel> and <h:message> components.
  • Placed into a "subHeader" (or other) facet of a table's column, which will automatically bind the filter to a containing table without using the for attribute (not applicable for <o:compositeFilter>).

Here's a simple example of specifying both an out-of-table filter and column filters:

<o:inputTextFilter for="employeesTable" expression="#{employee.firstName} #{employee.lastName}"/>
...
<o:dataTable id="employeesTable" var="employee" ...>
  <o:column ...>
    <f:facet name="subHeader">
      <o:comboBoxFilter/>
    </f:facet>
    <h:outputText value="#{employee.position}"/>
  </o:column>
  <o:column ...>
    <f:facet name="subHeader">
      <o:dropDownFieldFilter/>
    </f:facet>
    <h:outputText value="#{employee.department}"/>
  </o:column>
  ...
</o:dataTable>

The expression attribute defines a value that will be searched for (or filtered) with this filter. As you can see in the example above this attribute can be omitted when filter tag is declared inside of column. In this case the filter will automatically detect the expression from the first output component (UIOutput descendant) displayed by the column. Though you can specify the expression attribute explicitly if it should differ from the autodetected one, or if there's no output component in a column.

Using Composite Filter

As opposed to the simple one-field filters like those defined with <o:inputTextFilter>, <o:dropDownFieldFilter>, and <o:comboBoxFilter> tags, the composite filter (defined with <o:compositeFilter> tag) is a complex type of filter where the user interactively builds search criteria for searching across one or more columns.

Just like the simple filters, composite filter can be placed anywhere on a page and bound to a table with the for attribute, as demonstrated in this example:

<o:compositeFilter for="employeesTable"/>
...
<o:dataTable id="employeesTable" var="employee" ...>
  <o:column ...>
    <h:outputText value="#{employee.position}"/>
  </o:column>
  <o:column ...>
    <h:outputText value="#{employee.department}"/>
  </o:column>
  ...
</o:dataTable>

This simple declaration attaches the composite filter to a table and makes it autodetect the set of columns, with their types and names from the attached table. Though you can turn off the autodetection functionality and specify the column data for this filter explicitly if the list of columns in this filter should be different than the autodetected one. See CompositeFilter documentation for details.

A composite filter doesn't conflict with the other filters attached to the same table, so you can for example optionally declare column filters as well, and the table will display the data that takes into account all of the attached filters.

The CompositeFilter component can also be used as a standalone filter where the user-composed filter criteria can be used by the application code without explicit attachment to a table. Please read the full information about using the composite filter on the CompositeFilter documentation page, and the sections below cover the details of using the simple filters.

Customizing Filtering Options

The <o:inputTextFilter>, <o:dropDownFieldFilter>, and <o:comboBoxFilter> filters can filter any type of data (through the expression attribute or the autodetected column expression). The converter for this type of data is detected by the filter automatically from the parent column or filter expression type (when expression is specified explicitly). It is also possible to specify the converter explicitly with the converter attribute or adding a a converter as a filter's child tag.

By default, the search is performed by substring if a filter is bound to a string type and by exact match for any other type of data. The exception is the <o:comboBoxFilter> filter which searches by exact match for all types of data by default. The default filtering condition can be changed using the condition attribute, which can take the following values:

  • "equals"
  • "contains" (applicable for only for String fields)
  • "beginsWith" (applicable for only for String fields)
  • "endsWith" (applicable for only for String fields)
  • "less"
  • "greater"
  • "lessOrEqual"
  • "greaterOrEqual"

It is also possible to invert the condition by prepending one of these values with not keyword. Here are examples:

<o:inputTextFilter condition="less" expression="#{product.price}" .../>
...
<o:dropDownFieldFilter condition="not contains" expression="#{product.features}" .../>

By default, the string values are compared in a case-insensitive way and this can be changed by specifying the caseSensitive attribute with a value of true.

The current filter value specified in the filter is reflected in the filter's value attribute, so you can bind this attribute to a backing bean if you'd like some default filtering values to be present when the page is shown, or to be able to save the user-specified values to a backing bean for processing or saving among page visits. The value attribute should be bound to a variable of type ExpressionFilterCriterion. An instance of this class holds the user-specified value in its arg1 property.

As mentioned above, <o:dropDownFieldFilter> and <o:comboBoxFilter> display a list of all values present in table records for the filter's expression. Though the automatically composed list can be replaced with the custom one using the options attribute that should return a collection of items of the same item type as values returned by the filter expression.

Customizing Filtering Behavior

The <o:dropDownFieldFilter> tag has the autosuggestion and autocompletion features turned on by default. Autosuggestion means automatically opening the drop-down list when the user starts typing, and filtering the options list based on the input. This behavior can be customized with the suggestionMode attribute, which accepts one of the following values:

  • "all" – the entire list of options will be shown regardless of input.
  • "stringStart" – only the items starting with the typed text will be shown.
  • "substring" – only the items containing the typed text will be shown.
  • "stringEnd" – only the items ending with the typed text will be shown.
  • "none" – no autosuggestion behavior takes place, which means that drop-down will not be automatically opened when the user starts typing in the filter field.

The delay and minimal set of typed characters when the drop-down is autoopened can be customized with the suggestionDelay and suggestionMinChars attributes.
Autocompletion is another related feature that completes the partially-specified value right in the field, and this behavior can be turned off by assigning false to the autoComplete attribute.

It is possible to restrict entering values in <o:dropdownFieldFilter> to a list of its options, which means that it won't be possible to enter a value that doesn't exist in its drop-down list, which makes the drop-down filter like combobox filter in functionality but with a different way of entering a value and different look. This can be turned on by specifying the customValueAllowed attribute with a value of false.

By default, the <o:inputTextFilter> and <o:dropDownFilter> filters have the autofiltering functionality turned on, which means that the table is automatically filtered as the user types the text in the field. The filtering is performed each time when the user stops typing in the field for a while. This autofiltering period can be changed with the autoFilterDelay attribute which should be specified as a milliseconds number. The autofiltering functionality can be turned off by specifying the autoFilterDelay attribute with a value of -1, which means that filtering will be performed when the user presses the Enter key or leaves the filtering field.

The <o:inputTextFilter> and <o:dropDownFieldFilter> filters can also be customized to have a limit on the number of typed characters with the maxlength attribute. By default it has a value of Integer.MIN_VALUE which means that there's no limit on the length of typed text.

Customizing Filter's Appearance

The drop-down and combobox filters display the following provide the following items for specifying special filtering conditions in addition to the filter value items:
In addition to the unique column values, the "comboBox" and "dropDownField" filter components provide three predefined filter values:

  • "<All> - displays all records, i.e. data is not filtered.
  • "<Empty> - displays only the records with empty values (only for combobox filters).
  • "<Non-empty> - displays all records with non-empty values (only for combobox filters).

The text for these items can be customized with the allRecordsText, emptyRecordsText, and nonEmptyRecordsText attributes respectively, and the style for these items can be customized with the predefinedCriterionStyle/predefinedCriterionClass attributes.

When using <o:inputTextFilter> and <o:dropDownFieldFilter>, you can specify the prompt text with the promptText attribute. The prompt text is a label or short instruction placed inside the filter field. The specified text will be shown to the user while the field is empty and disappear once it gets input focus. The style of prompt text can be customized with the the promptTextStyle and promptTextClass attributes.

All of the <o:inputTextFilter>, <o:dropDownFieldFilter>, and <o:comboBoxFilter> tags have the following common attributes:

Attribute Description
style/styleClass A style for the filter component.
rolloverStyle/rolloverClass A style for the filter component in rollover state (except <o:comboBoxFilter>).
focusedStyle/focusedClass A style for the filter component in rollover state (except <o:comboBoxFilter>).
tabindex, accesskey, title, dir,
lang
The standard attributes for input tags.

There are also many drop-down field specific attributes in the <o:dropDownFieldFilter> tag. These are attributes such as buttonAlignment, listAlignment, listStyle, listItemStyle, etc. They have the same meaning as their counterparts in the <o:dropDownField> tag. Please see the DropDownField documentation for the description of these attributes.

Using Dynamic Loading

The DataTable component supports dynamic data loading for sorting, filtering, and pagination features using Ajax technique. The useAjax attribute specifies whether or not to use Ajax (by default, it is "true").

If Ajax is not used, when the DataTable component requires data update, the entire page is submitted and re-rendered completely with new data for the DataTable. With Ajax, the page is submitted "behind the scenes" with only the DataTable component being re-rendered.

Specifying the content of the "above" and "below" facets

The "above" and "below" facets are updated during any actions involving Ajax in the DataTable component: sorting, pagination, filtering and reloading the DataTable with Ajax component. The following rules are used for placing the components in the "above" and "below" facets:

  • If a component located in the "above" and "below" facet is expected to change as a result of an Ajax request, it should have the id attribute specified in order for this component to be re-rendered during the Ajax request. If there are many such components inside the same facet, you should wrap them into any other component or HTML tag that has the id.
  • If a certain component is changing its rendered attribute during an Ajax request, this component should be placed in some container component (such as <h:panelGroup>) with the id attribute specified.

Note that DataTable component is a naming container (it implements the NamingContainer interface), which means that it introduces a separate naming scope for all of its child components and facets, and you shouldn't worry about the table's child/facet ids to clash with components outside of the table.

Here is an example:

<o:dataTable ...>
...
<f:facet name="below">
  <h:panelGroup id="panelGroup">
    <o:dataTablePaginator id="paginator"/>
    <h:outputText value="#{BackingBean.value}"/>
  </h:panelGroup>
</f:facet>
</o:dataTable>

Row Selection

The row selection feature lets the user select one or more rows in the DataTable component. There are two row selection modes available: single and multiple.

By default, when the selection feature is turned on, the user can change the selection on the client-side. If you don't want to let the user change the selection, set the enabled attribute of the <o:singleRowSelection> or <o:multipleRowSelection> tag to "false".

The DataTable component provides a number of ways enabling the user to select rows. The user can do it by clicking on the row(s), or using the keyboard keys (see the section Keyboard Navigation for details), or selecting check boxes next to the rows in a special "selection column" (see the section Using a Selection Column for details). All these ways are configurable.

The DataTable component also provides a special "checkbox column" that can be used as an alternative of or in addition to the "selection column". See the section Using a Checkbox Column for more information.

You can customize the appearance of a selected row(s) including the background, text style, etc. using appropriate style attributes provided for each selection mode.

In order for the row selection feature to function properly, additional requirements are imposed on specifying the table data source.

Note that selected rows retain their selection state even if they are not currently visible either because of the applied filtering or pagination.

Single Selection Mode

You can provide single row selection in the DataTable component by using the <o:singleRowSelection> tag. To detect which row is currently selected or change selection, the <o:singleRowSelection> tag provides two value-binding attributes that can be bound to a backing bean:

  • rowData - Defines the row data object for a currently selected row. A value of null means no row is currently selected. Note that if when using this attribute, the row data objects provided by the application should be serializable and correctly implement the equals and hashCode methods.
  • rowIndex - Defines the index of a selected row. The index of the first row is "0". If pagination or filtering are applied to the DataTable component, only the rows that are currently visible can be addressed by this attribute (unlike the rowData attribute). A value of "-1" means no row is currently selected or a selected row is not visible because of another page being selected or filtering being applied.

If both attributes are specified but reference different rows, rowData takes precedence.

The following example shows configuration of single row selection:

<o:dataTable var="product"
             value="#{ProductsList.products}" >
  <o:singleRowSelection
          rowData="#{ProductList.selectedProduct}"/>
  <o:column>
    <f:facet name="header">
      <h:outputText value="name"/>
    </f:facet>
    <h:outputText value="#{product.name}" />
  </o:column>
</o:dataTable>

Note that when the user changes selection, a newly selected row is highlighted on the client side without any interaction with the server. So the properties bound to the rowData and rowIndex attributes are updated only when the form containing the DataTable component is submitted to the server. However, it is possible to execute an action right on selection change. You can do it in two ways:

  • Using the onchange attribute of the <o:singleRowSelection> tag. This is a client-side event attribute, where you specify the JavaScript code that should be executed every time the user changes selection.
  • Using the action attribute of the <o:singleRowSelection> tag. The use of this attribute is similar to the action attribute of the <h:commandButton> or the <o:commandButton> tag. The attribute can either specify a string defining the static outcome of the selection change action, or it can be defined as a method-binding expression, so that you can execute any Java code on the server when the user changes selection. In any case, defining the action attribute causes form submission on selection change.
  • You can also turn on the Ajax mode where the Ajax request will be automatically executed when the user changes selection. This can be done using the render attribute where you can specify the list of components that should be reloaded with Ajax when the selection is changed. This functionality is convenient for use cases when you need to update some components that depend on the currently selected item. The usage of the render attribute is the same as that for the <o:commandButton> tag. Note that when the render attribute is specified, the table and all its data including selection is submitted to the server for processing. If the action attribute is specified, the appropriate server-side action will also be executed during the Ajax request. By default, no components outside of the table are submitted and thus only table parameters themselves are available on the server during the Ajax request, though you can include additional components into the list of submitted components using the execute attribute. See the details on using the render and execute attributes in the CommandButton documentation.

The following examples shows the usage of the action attribute.

<o:dataTable var="product"
             value="#{ProductsList.products}" >
  <o:singleRowSelection
          rowData="#{ProductList.selectedProduct}"
          action="#{ProductList.processProductSelection}"/>
  <o:column>
    <f:facet name="header">
      <h:outputText value="name"/>
    </f:facet>
    <h:outputText value="#{product.name}" />
  </o:column>
</o:dataTable>

You can specify whether row selection can be made with the mouse or keyboard (or both) by setting the mouseSupport or keyboardSupport attributes of the <o:singleRowSelection> tag. Both attributes are "true" by default.

To apply a style for a selected row, use the style and styleClass attributes of the <o:singleRowSelection> tag. Note that these attributes are targeted at customizing the visual style according to the specified CSS declarations, but do not specify which HTML tags will be affected to achieve this. That is, these styles can technically be applied to different HTML tags depending on the browser or other conditions to ensure as uniform cross-browser appearance of the specified styles as possible. In most cases using these attributes is recommended.

There is also an additional rawStyleClass attribute which can be used if it is important to guarantee applying the specified CSS class(es) to the row tags themselves. In contrast with the style and styleClass attributes, this attribute might result in a browser-dependent display of styles, but it can be required if some other CSS declarations in your web design depend on a certain class name to be applied strictly to the row tags.

Note that, in general, it is not recommended to create a design that depends on the way that component's HTML is rendered. As a solution, the dedicated component's xxxStyle/xxxClass attributes should be used for styling different parts of components instead.
            <p>The <b><cite>DataTable</cite></b>'s rows in the current version are rendered with the usual HTML <tt>
                &lt;tr&gt;</tt> and <tt>&lt;td&gt;</tt> tags, and there is no intention to change it in the future
                currently, but it is possible that this will change at some point, so there's no guarantee that the
                <b>rawStyleClass</b> (and other "raw" classes) will be applied to the <tt>&lt;tr&gt;</tt> tags then.
            </p>
Multiple Selection Mode

With the DataTable component, the user can select any ranges of rows, whether contiguous or not. To set multiple selection mode for the DataTable component, use a child <o:multipleRowSelection> tag. The only difference between specifying single and multiple selection is that <o:multipleRowSelection> has the rowDatas and rowIndexes attributes instead of rowData and rowIndex.

The rowDatas attribute must be defined as a value-binding expression that references a list, set or array of row data objects. Note that when this attribute is used, the row data objects provided by the rowDatas attribute should be serializable and correctly implement the equals and hashCode methods. The rowIndexes attribute must be bound to a list, set or array of java.lang.Integer instances. Empty lists mean an empty selection.

All other features, including selection change notifications and styles, can be configured in the same way as for the single selection mode.

The following example shows the DataTable component configured for multiple row selection.

<o:dataTable var="product"
             value="#{ProductsList.products}" >
  <o:multipleRowSelection rowDatas="#{ProductList.selectedProducts}"/>
  <o:column>
    <f:facet name="header">
      <h:outputText value="name"/>
    </f:facet>
    <h:outputText value="#{product.name}" />
  </o:column>
</o:dataTable>
Using a Selection Column

The DataTable component provides a special "selection column" that displays check boxes for multiple row selection or radio buttons for single row selection. The selection column is an alternative way for the user to change selection and see which row(s) is selected. The selection column is denoted by the <o:selectionColumn> tag.

For multiple selection mode, you can add a child <o:selectAllCheckbox> tag to the "header" or "footer" facets (or both) of the table and/or any of its columns. This will display a check box which when clicked will trigger selection for all table rows.

The following example shows a selection column configured for selecting multiple rows in the DataTable component.

<o:dataTable var="product"
             value="#{ProductsList.products}" >
  <o:multipleRowSelection ... />
  <o:selectionColumn>
    <f:facet name="header">
      <o:selectAllCheckbox />
    </f:facet>
  </o:selectionColumn>
  <o:column>
    <f:facet name="header">
      <h:outputText value="name"/>
    </f:facet>
    <h:outputText value="#{product.name}" />
  </o:column>
</o:dataTable>
Using a Select Row Checkbox

When using multiple selection, it's also possible to display the row selection check-box in any place of a row using the <o:selectRowCheckbox> tag. Check-boxes added in this way work in the same way as check-boxes displayed by the selection column, and you can use these features interchangeably depending on the design requirements of your application. You can actually use selection column and SelectRowCheckbox component at the same time if needed. The <o:selectRowCheckbox> tag can be placed in any place of any table's column similar to any other regular components displayed in table's columns.

The <o:selectRowCheckbox> tag has most the attributes of <o:selectBooleanCheckbox> tag, which allows customizing all of the check-box'es appearance aspects, such as an ability to display custom check-box images in different states.

Here's a simple example of placing the SelectRowCheckbox into a column near the column's text. Note that the SelectAllCheckbox can still be used here if needed, even without using a selection column.

<o:dataTable var="product"
             value="#{ProductsList.products}" >
  <o:multipleRowSelection ... />
  <o:column>
    <f:facet name="header">
      <h:panelGroup>
        <o:selectAllCheckbox /> <h:outputText value="name"/>
      </h:panelGroup>
    </f:facet>
    <o:selectRowCheckbox/> <h:outputText value="#{product.name}" />
  </o:column>
</o:dataTable>

Cell Selection

The cell selection feature lets the user select one or more cells in DataTable component. There are two cell selection modes available: single - <o:singleCellSelection> and multiple - <o:multipleCellSelection>.

There are a lot of common/identical behavior between row selection and cell selection.
These attributes are provide the same functionality as in rowSelection: action, execute, render, rendered, enabled
and events - onchange, onajaxend, onajaxstart, onerror, onsuccess (see the section Row Selection for details).

The delay attribute specifies the delay in milliseconds that should elapse after an event that activates this component to start an actual request for reloading components, so it allows to reduce number of ajax requests.

As in row selection, in cell selection you can specify whether cell selection can be made with the mouse or keyboard (or both) by setting the mouseSupport or keyboardSupport attributes of the <o:singleCellSelection>/ <o:multipleCellSelection> tags. Both attributes are "true" by default.

You can specify for selection feature which cells are can/cannot be selectable using cellSelectable/selectableCells methods binding attributes.
Backing bean method for cellSelectable should return boolean value and it is called for every cell. You can use the Request-Scope Variables to detect the row and column of the current column. E.g., if you have the rowIndexVar="rowIndex" declaration in your <o:dataTable> tag, you can retrieve this parameter as follows from the backing bean:

int rowIndex = Faces.var("rowIndex", Integer.class);

Backing bean method for selectableCells should return array of boolean values for each row. (Each boolean value corresponds for column in order as they were declared). You can access to rowIndex parameter as it is used in cellSelectable.

In cell selection you can specify fillDirection attribute which specifies how selection will work - as in text documents ("document") or as in spreadsheet applications("rectangular"). If "document" mode has chosen , the cell selection wll work as in text documents.
Note that mouse/keyboard navigation for "document" mode has differences from "rectangular" mode.

Note that using cellSelectable and selectableCells attributes together is not allowed.

Note that using cell selection feature with row grouping feature is not allowed.

You can customize appearance of selected cell(s) using style/styleClass attributes and appearance of selection cursor using cursorStyle/cursorClass attributes.

Keyboard navigation is allowed with such keys and combinations of keys: Up, Down, Left, Right, Home, End, Ctrl+Home, Ctrl+End

Single Cell Selection

You can provide single cell selection in the DataTable component by using the <o:singleCellSelection> tag.
To define which cell is selected, the <o:singleCellSelection> tag provides value-binding attribute cellId which can be bound to a backing bean.
The cellId attribute could be binded to field of org.openfaces.component.table.CellId type which has fields:

  • columnId - Defines the id of column for currently selected cell.
  • rowData - Defines the row data object for a currently selected cell.

If cellId attribute is assigned to null then it means no cell is currently selected.

The following example shows configuration of single cell selection:

<o:dataTable id="bookSingleSelection"
		var="book" value="#{BookList.books}">
  <o:singleCellSelection cellId="#{BookList.cellId}"/>
  <o:column id="title" header="Title">
        <h:outputText value="#{book.bookTitle}"/>
  </o:column>
</o:dataTable>
Multiple Cell Selection

To set multiple selection mode for DataTable component, use a child <o:multipleCellSelection> tag.
There is only one main difference between this tag and <o:singleCellSelection>:

  • cellIds instead of cellId attribute - it is a value-binding expression that references a list, set or array of CellId objects which were considered above. Empty list means empty selection.

All other features, including selection change notifications and styles, can be configured in the same way as for the single selection mode.

Also, mouse/keyboard support has been extended in multiple cell selection.
You can select cells as linked as separate between them.
Linked multiple cells selection:

  • Drag and Drop - a user presses mouse button and then drags over the table.
  • A user selects cell by mouse click and then clicks on other cell with pressed Shift button.

Separate multiple cells selection:

  • A user selects cells with help of mouse/keyboard and then clicks on separate cell with pressed Ctrl button. After that he can use standard keyboard/mouse navigation for further selection.

Keyboard support has been extended - support for combinations Shift + all keyboard keys, mentioned in Cell Selection is provided.

The following example shows the DataTable component configured for multiple cell selection.

<o:dataTable id="bookSingleSelection"
	var="book" value="#{BookList.books}">
	<o:multipleCellSelection cellIds="#{BookList.list}"
            cursorStyle="color:red"
            selectableCells="#{BookList.getSelectableCells}"
	    delay="500"/>
       <o:column id="title" header="Title">
           <h:outputText value="#{book.bookTitle}"/>
       </o:column>
</o:dataTable>

Using a Checkbox Column

The DataTable component provides a "checkbox column", which is a special visual component that is rendered as a column of check boxes whose values are not stored in the row data object. You can use it as an alternative of or in addition to multiple selection or when you need to implement complicated selection models.

To add a checkbox column to the DataTable component, use the <o:checkboxColumn> tag. It has two attributes, rowDatas and rowIndexes, which should be defined as value-binding expressions that reference a list of row data objects and java.lang.Integer instances, respectively. These attributes are mutually exclusive and you will normally use just one of them, which suits application logic more closely. Please note that the nodePaths attribute is only applicable for the TreeTable component. In addition, you can add a child <o:selectAllCheckbox> tag to the "header" or "footer" facets (or both) of the <o:checkboxColumn> (for more information, see the section Using a Selection Column).

Note that the checkbox column imposes the same requirements on the data source as does the selection feature: row data objects should be serializable and correctly implement the equals and hashCode methods, or the rowKey attribute should be provided.

It is also important to note that while the selection column (see the section Using a Selection Column) is just an alternative way to manage selection, the checkbox column stores a list of selected rows independently of the selection and independently of each other (when several checkbox columns are used in the same DataTable component). For example, you can have selection and two checkbox columns that can all be bound to their own properties.

It is also possible to optionally disable or hide check boxes for some rows depending on application logic. This can be done using the disabled and visible attributes of <o:checkboxColumn> tag respectively. These attributes can be specified as a simple true/false value, or as an EL expression, which uses any of the row variables (the ones declared with DataTable's var and rowIndexVar attributes).

The following example shows the usage of the checkbox column with some of the check boxes disabled depending on row data objects.

<o:dataTable var="product"
             value="#{ProductsList.products}" >
  <o:checkboxColumn rowDatas="#{ProductList.checkedProducts}" disabled="#{product.inStock}">
    <f:facet name="header">
      <o:selectAllCheckbox />
    </f:facet>
  </o:checkboxColumn>
  <o:column>
    <f:facet name="header">
      <h:outputText value="name"/>
    </f:facet>
    <h:outputText value="#{product.name}" />
  </o:column>
</o:dataTable>

Row Grouping

It is possible to add the interactive row grouping capability to the DataTable component, which will allow the user to group the table by the values of its columns. When a table is grouped by any of its columns, it displays a two-level tree structure instead of a plain record list. The top-level items display the group header rows, and each group header row has a list of sub-records that corresponds to that group. It is also possible to group the table by more than one column which will result in displaying a deeper tree structure, where the top-level groups will contain other sub-groups.

The row grouping capability can be added to a DataTable component by placing the <o:rowGrouping> tag as a child of the <o:dataTable> tag, and configuring one or more types of user interfaces for controlling grouping, as follows.

There are three ways of how a user can change table's grouping structure. Each of them is optional and can be turned on/off individually:

  • Grouping with drag&drop of column headers. It can be enabled by placing the <o:groupingBox> tag inside of the "header" facet of the <o:dataTable> tag. Doing so displays a special area above the table which displays the current table's grouping structure and allows to change it with drag&drop of the column headers to/from the grouping box itself. See below for more information on grouping box.
  • Grouping by clicking on column headers. This way of controlling grouping can be turned on by declaring the attribute groupOnHeaderClick with a value of true for the <o:groupingBox> tag. This feature actually extends the existing sorting behavior, which sorts a column by clicking on its header with additionally grouping a table by that column. Note that this way of grouping works only on sortable columns (the columns which have the sortingExpression attribute defined).
  • Grouping via column menus. This way of controlling grouping can be turned on by adding the column menu feature by placing the <o:columnMenu> tag into the "columnMenu" facet of the <o:dataTable> tag. See the Displaying Column Menus section for more information on configuring the style and contents of column menus.

It is possible to combine all of these grouping UIs in the same table in any combination. They allow grouping a table by more than one column simultaneously, except the second one, which always results in a one-column grouping when the column header is clicked. You can add more columns with the other approaches if needed though (using drag&drop or column menus).

Note that when the grouping feature is turned on, it is possible to use only the groupable columns for grouping the table. A groupable column is a column defined by <o:column> tag, which has either sortingExpression or groupingExpression attributes defined (see below for more details). So if the columns in your DataTable are already sortable then no additional configurations are required.

Here's an example that shows how to add all of the three grouping UIs described above to your <o:dataTable> tag:

<o:dataTable var="bank" value="#{BanksList.banks}" ...>

<o:rowGrouping groupOnHeaderClick="true"/> <f:facet name="header"> <o:groupingBox/> </f:facet> <f:facet name="columnMenu"> <o:columnMenu/> </f:facet>

<o:column sortingExpression="#{bank.institutionName}" ...> <h:outputText value="#{bank.institutionName}"/> </o:column> <o:column sortingExpression="#{bank.averageAssets}" ...> <h:outputText value="#{bank.averageAssets}"/> </o:column> ... </o:dataTable>

Basically, this is all that is needed to add the grouping capability to the table. The rest of the grouping documentation describes the additional customizations and specifics which might be required in your case.

Specifying the Grouping Value

When the table is grouped by any of its columns, its records are combined into groups where each group contains the records with the same grouping value for that column. A grouping value is a value defined by the sortingExpression attribute, or a groupingExpression attribute, as described in more detail below. The grouping value should either be of any primitive type, or it can be an object which implements the java.io.Serializable and java.lang.Comparable interfaces.

If you'd like to make some of your non-sortable columns available for grouping anyway, you can declare the groupingExpression attribute for the appropriate <o:column> tags. The groupingExpression attribute should be declared in the same way as the sortingExpression one – it should specify the value expression that refers to the row-dependent value which will be used when grouping a table by that column (a so called "grouping value").

In some cases it might be useful to define a grouping behavior different from the one used for sorting, for example when you should combine several different but similar in some way values into the same group. In this case, you can retain the sortingExpression intact, and declare the groupingExpression attribute which introduces the proper behavior. To do this, the method that is bound to your groupingExpression attribute should analyze the column's value and return the same value (usually a string), that describes all of the similar values that fit in this group. This is actually the value that will be displayed in the group header row for the appropriate group.

This can particularly be useful for grouping records by their ranges rather than individual values. You can see such behavior on the "Average Assets" column of the OpenFaces live demo, and here is an example of how this can be implemented:

<o:dataTable var="bank" value="#{BanksList.banks}" ...>

<o:rowGrouping groupOnHeaderClick="true"/> ...

<o:column sortingExpression="#{bank.averageAssets}" groupingExpression="#{BanksList.averageAssetsRange} ...> <h:outputText value="#{bank.averageAssets}"/> </o:column> ... </o:dataTable>

Note the "#{BanksList.averageAssetsRange}" expression which points to a backing bean method that should return the range for the current row. Here's how this method might be implemented:

    public String getAverageAssetsRange() {
        Bank bank = Faces.var("bank", Bank.class);
        int averageAsset = bank.getAverageAssets();
        if (averageAsset <= 50000)
            return "< 50,000";
        if (averageAsset <= 100000)
            return "50,000 - 100,000";
        if (averageAsset <= 200000)
            return "100,000 - 200,000";
        // ... return as many ranges as is appropriate
        return "> 10,000,000";
    }

By default, when you group a table by one of its columns by dragging their columns to a grouping box, or via column menu, the appropriate columns are automatically hidden, while the table is grouped by those columns. This behavior can be changed, and the columns can still be visible even when grouping is performed by them by specifying the rowGrouping tag's hideGroupingColumns attribute to false.

Customizing Group Header Rows

Group header rows consist of one cell that spans across all table's columns. By default, it displays the name of the column by which grouping is performed, and the appropriate value that is common for all records in this group. The way that group header text is formatted can be customized using the groupHeaderText attribute. It should be declared as a value expression that defines a pattern of how column header and grouping value should be combined. By default it has the following value: "#{columnHeader}: #{groupingValueString}".

The columnHeader and groupingValueString are the variables that, as their name suggests, contain string values for current column header and the current grouping value string respectively. There is one more variable which can be used here if needed: groupingValue, which contains a "raw" non-string grouping value, which might be useful in some more complex scenarios. The names of these variables can be customized using the columnHeaderVar, groupingValueStringVar and gropuingValueVar attributes respectively, if needed to avoid clashes with other variables on the same page.

The converter which is used for converting the grouping value into the displayed string can optionally be customized using the groupingValueConverter attribute of each respective <o:column> tag.

If you need to show a non-text content in the group header row, you can define the "groupHeader" facet. The component(s) in this facet can use the same variables as the text version described above: columnHeader, groupingValue and gropuingValueString.

The following example shows a header row which contains a column header name and an image.

<f:facet name="groupHeader">
  <h:panelGroup>
    <h:outputText value="#{columnHeader}: "/>
    <h:graphicImage url="#{groupingValue.imageUrl}"/>
  </h:panelGroup>
</f:facet>

If this facet is defined, its content is shown instead of the default text template. Please note, that the content of this facet is placed instead of the entire text template, and not instead of just the column value string. So the column header name will not be shown if not defined in the facet explicitly, as can be seen in the example above.

The style for the group header rows can be customized using the groupHeaderRowStyle and groupHeaderRowClass attributes of the <o:rowGrouping> tag.

Other Types of Group Header and Footer Rows

Besides the "groupHeader" facet which allows specifying the content for the "main" group header, it's also optionally possible to specify the "inGroupHeader" facet for any of the table's column. The components specified in this column are similar to the column headers specified in the "header" facet, but the column headers specified here are displayed in the special header row which is displayed inside of each group rather than at the top of the table, which might be useful if you'd like to duplicate column headers inside of the group, or display some other text/information/components inside of the so-called "in-group header" row.

Similarly, there are two facets which can optionally be specified to display group footers:

  • "inGroupFooter" facet. This facet is analogous to the "inGroupHeader" facet described above, and allows specifying the content that should be displayed for each column inside of each group.
  • "groupFooter" facet. This facet is analogous to the "groupHeader" one. Specifying this kind of footer for any particular column will make the appropriate footer rows to be displayed when the table is grouped by that column. It is displayed under the "in-group" footer row, and it consists of one cell that spans across all columns.

The behavior of how the in-group footers behave when the user expands/collapses the groups can be customized. By default, they are expanded/collapsed along with the group's records (e.g. they are hidden when the group is collapsed). However, it is possible for them to stay visible even when the group is collapsed under the group header by assigning false to inGroupFootersCollapsible and groupFootersCollapsible attributes respectively.

Maintaining the Grouping and Expansion States

Grouping state defines the set of columns by which the table is currently being grouped by. You can bind the groupingRules attribute of <o:rowGrouping> tag to be able to control grouping state and maintain its state between different visits of the same page. This attribute should be bound to a property of type java.util.List<org.openfaces.component.table.GroupingRule>. If you'd just like to save grouping state across page visits, then you should just ensure that this property is stored in a scope has an appropriate life-time.

You can also use this attribute to control the grouping state from your Java code, for example to be able to group the table by certain columns programmatically. To do this, you should just make the getter method for this property return the list which has one GroupingRule instance per each column by which table should be grouped. The GroupingRule class has two properties, which should be specified in this case:

  • columnId: String – id of a column which should be grouped (this should match the value of the id attribute of the appropriate <o:column> tag);
  • ascending: boolean – a flag which specifies whether the groups should be sorted in an ascending order (true), or in a descending order (false).

Expansion state is the information on which groups are expanded, and which are collapsed. You can bind the expansionState attribute of <o:rowGrouping> tag to specify the default expansion state, and maintain expansion state across different page visits. This attribute can be specified in two ways. If you don't have to save expansion state across page visits, and just need to specify the default expansion state, then you can just specify any of the two predefined values for this attribute right on your xhtml page: "allExpanded", or "allCollapsed". The default value is "allExpanded", which means that all groups are expanded by default. If you need to save expansion state across page visits, then you should bind this attribute to a property of type ExpansionState, and save the value of this property in a scope that has a proper life-time. If you're using this approach and still need to specify the default expansion state, then you should just initialize this property with one of these two implementations of the ExpansionState interface: AllNodesExpanded, or AllNodesCollapsed. Both of these classes have a no-arg constructor, so you should just create an empty instance and assign it to your property.

Using the Grouping Box

As it was mentioned above, when the grouping box is enabled for the table, the user can drag the column headers to and from the grouping box to change the table's grouping structure. It is also possible to swap the positions of column headers in the grouping box to change the grouping priority for the respective columns.

The style for the grouping box can be customized using the style and styleClass attributes of the <o:groupingBox> tag.

When the table is not grouped, it displays a prompt text which gives a small hint to the user on how to use it. This text and its style can be customized promptText, and promptTextStyle/promptTextClass attributes of the <o:groupingBox> tag.

When the table is grouped, it displays the tree-like structure of column headers for columns by which the table is currently being grouped. The style of these column headers is the same as the one in the main table's column headers row, but it is possible to override CSS style for them using the headerStyle/headerClass attributes. The distance by which each respective column in this symbolic tree structure is offset relative to the previous one can be customized using the headerHorizOffset and headerVertOffset attributes. The style for the line that connects column headers in the grouping box can be customized with the connectorStyle attribute. This attribute should be specified in a truncated CSS form, like this: "1px solid black", or "2px dotted gray", etc.

Customizing the Column Menu

When a column menu is added to the table with row grouping feature, as described above, it contains two additional items, which allow grouping a table by column, and excluding a column from grouping. These menu items are automatically shown or hidden depending on their applicability to the context where the menu is displayed.

In case if you need to customize the content of the menu (to add custom items, and/or change texts/styles in the existing ones), this can be done by redefining the content of the menu, as described in the Displaying Column Menus section. The row grouping feature adds two more menu item tags in addition to the ones listed there, and you can use these items when redefining the menu:

  • <o:groupByColumnMenuItem> tag – displays a menu item which adds the appropriate column into the grouping structure (groups the table by that column in addition to the current grouping columns);
  • <o:removeFromGroupingMenuItem> tag – displays a menu item which excludes the appropriate column from the grouping structure.
    These tags has all of the customization attributes of the usual <o:menuItem> tags except some attributes which are not applicable for these ones, such as subMenuImageUrl, which is unavailable because this item cannot have a sub-menu, or action attribute because these items have their own built in actions.
Interoperability with Other Features

A table with row grouping feature can still have the usual selection support (single or multiple), but since it also displays group header records in addition to the regular data records, these records can be selected as well, so the row grouping feature introduces two modes to be able to control how they should be handled. The way that selection for such records is processed can be customized with the selectionMode attribute of <o:rowGrouping> tag. It can have one of the following two values:

  • "dataRows" – this mode is useful when it is needed to track selection only for the data rows, and not for the group header rows. This mode means that when the table saves the selection through the bindings declared in the <o:singleRowSelection> or <o:multipleRowSelection> tags (in their rowData, and rowDatas attributes respectively), it doesn't include an information on the group headers that might actually be selected on client-side (which is required for the navigation purposes anyway).
  • "allRows" – this mode is useful when it is needed to track selection for both the regular data rows, and group header rows. There's one peculiarity that should be taken care of when this method is used. Since this mode can pass different types of objects to the methods bound to the rowData or rowDatas attributes of selection tags, these methods should be prepared to receive any type of objects, and analyze the type of objects that are passed to it to distinguish between row headers and data objects. This practically means that the type of these properties should be java.lang.Object (in case of rowData attribute), and a collection of java.lang.Object instances (in case of rowDatas attribute). The type of group header row objects is RowGroupHeader.
The row grouping feature is currently not compatible with the pagination feature.

Summary Calculation

It is possible to make the DataTable component calculate the summary value across the displayed rows automatically. There are two parts of the API for turning on and controlling this feature:

  • Table-wide customization API, which allows turning on the summary calculation feature for the entire DataTable component. This API allows allows you to add the summary calculation feature to all columns where summary can be calculated.
  • Fine customization API, which can be used to display summary values for some specific column(s), and fine-tune summary calculation feature on a per-column basis if table-wide customization is used.

Note that both of these two kinds of API can be used on their own or at the same time. That is, you can turn on the summary calculation feature for the entire table, and then use fine customization API in the places where the automatically-detected settings are not applicable according to application's needs.

Below is the description for each of these types of API.

Table-Wide Customization API

You can turn on the summary calculation feature for the entire DataTable by adding the <o:summaries> tag inside of the <o:dataTable> tag. This will add the summary calculation feature for all of the columns whose summary can be calculated (please see the Summary Calculation Values section below to see how columns have to be declared for the summary calculation feature to work properly).

If columns are declared properly, this is the only change that is required to turn on the summary calculation feature for the entire table. This works by inspecting each DataTable's columns and analyzing whether the type of values displayed in that column is one of the types that can be used for summary calculation (see the Summary Calculation Values and the Adding Support for Custom Types sections on the information on supported types). If the column was detected as being applicable for summary calculation, this will result in displaying the summary values in the "footer" and "inGroupFooter" facets of that column if those facets are not declared explicitly on that column. If any of these facets is already declared then the components specified in the appropriate facet are displayed instead of the summary value, and you have to add add the <o:summary> component to that facet explicitly to display the summary value in that column (see the Fine Customization API section for the description of the <o:summary> tag).

Here's an example of how this feature can be turned on for a simple table:

<o:dataTable value="#{myBean.item}" var="item">
  <o:summaries/>

<o:column caption="Name"> <h:outputText value="#{item.name}"/> </o:column> <o:column caption="Cost" value="#{item.cost}"> <h:outputText value="#{item.cost}"/> </o:column> <o:column caption="Left In Stock" value="#{item.leftInStock}"> <h:outputText value="#{item.leftInStock}"/> </o:column> </o:dataTable>

This makes the sum of the "Cost" and "Left In Stock" columns to be displayed in the table's footer, and allows the user to change the summary calculation function to another one. By default, there are the Sum, Avg, Min, Max and Count functions, and it is possible to add application-specific ones as described in the Adding Support for Custom Functions section below. Note the <o:summaries> tag, in this example, and the value attribute on the columns which need the summary calculation functionality. The value attribute identifies the value by which the summary should be calculated, see the Summary Calculation Values section for the details.

The <o:summaries> tag has the following optional attributes:

  • footerVisible : boolean (true by default) – specifies whether the <o:summaries> component should display summaries in the table's footer row. This attribute does not affect the <o:summary> tags that have been placed into the table's footer explicitly.
  • inGroupFootersVisible : boolean (true by default) – specifies whether the <o:summaries> component should display summaries in the table's in-group footer rows. This attribute does not affect the <o:summary> tags that have been placed into the table explicitly.
  • pattern : value expression – specifies the pattern that specifies how the calculated summary value and function name is combined to display the text for summary values. This expression can use the following two request-scope variables: function and value.
  • functionEditable : boolean (true by default) – specifies whether the user can change the function by which the summary is calculated with a context menu for the respective summary value.

If any of the automatically calculated summary values do not match the application's preferences, you can override the automatically-detected settings by placing the <o:summary> tag(s) in the appropriate tags and declaring their attributes appropriately (see the Fine Customization API section below).

Summary Calculation Values

Note that the <o:column> tags in the example above have the value attribute defined. This attribute specifies the value by which the summary for this column is to be calculated, i.e. the values whose sum (or other function) will be displayed in the footer. The value attribute is actually not mandatory for simple columns like the one described above. The summary calculation feature will look for a summary calculation expression inside of the first UIOutput component (such as <h:outputText>) in that column, in case of absence of the explicitly specified value attribute on a column. Nevertheless, you might find having the value attribute defined explicitly for all columns anyway to be a good practice, to avoid summary calculation functionality being dependent on column's sub-components.

When using the fine customization API, it is also possible to specify the summary calculation expression explicitly irrespective of how columns are declared (see the Fine Customization API section below).

The type of values provided by the column's value attribute (or the one derived automatically from the UIOutput component), should be either one of the primitive types, except boolean, one of their wrapper types, such as java.lang.Integer, java.lang.Float, etc., or the java.util.Date type. It is also possible to add support for custom application-defined types for them to be able to be used with the summary calculation feature (see below).

Fine Customization API

This kind of API basically allows you to display individual summary values at arbitrary places of the table and fine-tune their settings on a per-summary basis. This way it is possible to override settings for certain summary values that were automatically detected when using the table-wide customization API, and place additional summary values in the places that the automatic summary placement (done by the <o:summaries> tag) function does not include.

An individual summary value can be displayed by placing the <o:summary> tag into one of the facets of the <o:dataTable> component, or into one of the facets of its <o:column> or <o:columnGroup> tags.

The Summary sub-component, defined by the <o:summary> tag can use different functions for calculating the resulting value of the displayed data. By default, it either calculates the number of displayed records, or calculates a sum of values of the column where it is inserted, depending on where it is placed. Here's a simple example of adding the summary calculation feature to a table:

<o:dataTable value="#{myBean.item}" var="item">
  <o:column caption="Name">
    <h:outputText value="#{item.name}"/>
  </o:column>
  <o:column caption="Cost" value="#{item.cost}">
    <f:facet name="footer">
      <o:summary/>
    </f:facet>
    <h:outputText value="#{item.cost}"/>
  </o:column>
  <f:facet name="footer">
    <o:summary/>
  </f:facet>
</o:dataTable>

The <o:summary> tag placed into the "footer" facet of the second column displays a sum of the values for that column, and the one placed into the "footer" facet of the table itself displays the number of displayed records.

If the table has the pagination feature turned on, the summary values are calculated over the records on the currently visible page, but not over the whole data set.

As it was mentioned in the Summary Calculation Values section above, the summary will be calculated over the values defined by the value attribute of the <o:column> tag. Note that it is also optionally possible to specify the expression by which the summary value is calculated in the <o:summary> tag itself using its by attribute, which is useful for the Summary components located inside of the table's facets (when displayed for the entire table, outside of columns). When this attribute is defined for the Summary component that resides inside of a column, it overrides the value that is defined in that column.

You can specify the converter that will be used to display the calculated summary value using the converter attribute of the <o:summary> tag, or by placing one of the converter tags inside of the <o:summary> tag.

Summary Calculation Functions

The function by which the summary value is calculated can be customized using the function attribute of the <o:summary> tag. It can take one of the following values:

  • "sum" – calculates the sum of the appropriate values;
  • "avg" – calculates the average of the appropriate values;
  • "min" – calculates the minimum value;
  • "max" – calculates the maximum value;
  • "count" – calculates the number of records;
  • a value binding expression that refers to a property of type SummaryFunction, which can be used for creating custom summary calculation functions.
Text Pattern

The text displayed by the Summary component includes both the function name and the calculated value separated by a colon by default. It is possible to customize this using the pattern attribute of the <o:summary> tag. It should be declared as a value binding expression that refers to any of the following variables in combination with an arbitrary characters:

  • function – the SummaryFunction instance that displays function name when converted to the string;
  • value – the calculated summary value;
  • valueString – the calculated summary value converted to string according to the current component's converter.

Here's a simple example of how this attribute can be defined:

...
<o:summary pattern="#{function} = #{valueString}"/>
...
Showing Group Summaries

The usage described above, when the Summary component is placed inside of one of the facets of the <o:dataTable> tag, or into the "header"/"footer" facets of the <o:column>/<o:columnGroup> tags results in calculating the summary values over all of the displayed records.

It is possible to place the <o:summary> component inside of the following facets of the <o:column> tag to display the summary values calculated over individual groups rather than the whole table's data:

  • "groupHeader" – displays the summary value in the group header row for groups composed by this column. Note that the contents of this facet overrides the default "Column name: grouping value" display, as noted in detail in the Customizing Group Header Rows section.
  • "groupFooter" – displays the summary value in the group footer row for groups composed by this column.
  • "inGroupHeader"/"inGroupFooter" – unlike the "groupHeader"/"groupFooter" facets that span across the whole row, the components specified in these facet are the visual analogs of the "header"/"footer" column's facets, so specifying components in these facets will result in a header/footer cell to be displayed in each column inside of each group.
Miscellaneous Customizations

Similar to the <o:summaries> tag, it is possible to customize whether the user can change the summary calculation function on a per-summary basis using the functionEditable boolean attribute (true by default).

Also, like in most of the other components, you can specify the style for the displayed text with the style/styleClass attributes, and event handlers with such attributes as onlclick, ondblclick, etc.

Adding Support for Custom Types

Only the primitive types and the java.util.Date type is supported by default, but it is possible to make the summary calculation feature work with your own custom types. To add support for a custom type, you should create an implementation of the abstract OrdinalType class. This class defines all of the operations that are required for summary calculation, and you should override the following methods:

  • boolean isApplicableForClass(Class valueClass) – should return true if this class can work with the values of the specified type,and false otherwise.
  • Object add(Object value1, Object value2) – computes a sum of the two values of the type described by this class, and the result of the same type.
  • Object divide(Object value, double by) – divides the custom-typed value by a double-typed value, and returns a custom-typed result.
  • Comparator getComparator() – returns a Comparator instance that can be used to compare the instances of types supported by this class. You can skip overriding this method, or return null if all values of the described type are supposed to implement the Comparable interface.

You can study the code of the predefined OrdinalType implementations to see an example of how such classes can be implemented: AnyIntegerType.java, AnyFloatingPointType.java, and DateType.java

Once you created the OrdinalType implementation, you have to register it in the org.openfaces.ordinalTypes application context parameter in the web.xml file. This parameter should be specified as a comma-separated list of fully-qualified class names for all custom types. Once your custom types are registered, the summary calculation feature can be used in the same way as with the built in ones.

Adding Support for Custom Functions

As it was mentioned in the Summary Calculation Functions section above, you can use your own custom summary calculation function implementations. In order to support a custom data type, you have to create an implementation of the SummaryFunction class, which will define how the standard operations on the values of that data type are performed. The main two methods which must be implemented are the following ones:

  • public String getName() – this method should return a name for the function, which will appear in the function list popup menu;
  • public Calculator startCalculation() – this method should create an implementation of the SummaryFunction.Calculator class which will perform the actual calculation.

Note that the same instance of the summary function implementation can be used for all tables in the application, so it shouldn't store any calculation results to avoid conflicts when being used on different tables or different table's columns. To assess an ability to use the same instance of the summary function several times, its startCalculation() method returns an implementation of the SummaryFunction.Calculator abstract class, which actually performs all of the calculations, and one instace of this class is created for each usage "session" of this summary function (when summary value should be calculated over a certain list of data entries). There is the following field which is available for implementations of this class and the following methods which have to be implemented for each implementation of the SummaryFunction.Calculator class:

  • protected Object accumulator – stores the intermediate result of calculation. This field must be updated by the addValue method, mentioned below, and is returned by the endCalculation method in its default implementation. This field has a value of null when an instance of Calculator is created. Of course you can add your own fields in custom function implementations if required during for the calculation process;
  • public void addValue(Object value) – this method is called for each value that has to be included into this session of summary calculation. An implementation of this method can update the accumulator field and/or other fields which the developer might add for the needs of calculation;
  • public Object endCalculation() – this methods should return the result of the calculation which summarizes all of the values that were provided to the prior addValue method calls on this instance. The default implementation of this method returns the value of the accumulator field, and you may skip overriding this method if the default implementation is acceptable.

You can see some of the predefined implementations to get an idea of how to implement your own custom functions: SumFunction.java, AvgFunction.java, MaxFunction.java, CountFunction.java.

Once you have implemented your own implementation(s) of the SummaryFunction class, you have to register them in the org.openfaces.summaryFunctions context parameter in the application's web.xml file for your custom function(s) to be displayed in the list when changing the current function through the popup menu. This parameter should be specified as a comma-separated list of fully qualified class names.

Handling Large Datasets

The DataTable component obtains a full set of data through its value attribute. Then, the obtained data gets automatically filtered, sorted and paginated by the DataTable component. This means that the default behavior of the DataTable requires that the entire set of data be retrieved and stored in memory. This is not always effective in terms of memory usage and performance, especially when the DataTable component works with a large dataset.

To solve this problem, the DataTable component provides the custom data providing feature. To enable it, set the customDataProviding boolean attribute of the <o:dataTable> to "true". In this case, it becomes the responsibility of an application developer to provide data that is already correctly paginated, sorted and filtered, instead of the DataTable component doing these tasks. In this way, it becomes possible to retrieve only needed data, for example, by issuing an appropriate query to the database. Another reason for using the custom data providing mode in addition to handling the large data sets is the fact that it provides the possibility to implement custom data sorting, filtering and pagination logic if required.

When the customDataProviding attribute is set to "true", the function that provides the data for the value attribute must be aware of the following request-scope variables in order to correctly provide data:

  • filterCriteria of type CompositeFilterCriterion - The filtering criteria that is currently specified for the DataTable component. This variable must be processed if there are any filters assigned to the DataTable component.
  • sortColumnId of type String - id of a column by which the DataTable component is sorted. This variable should be used to provide the properly sorted data.
  • sortAscending of type boolean - The sorting order in which the column is sorted. This variable in conjunction with the sortColumnId is required to provide the properly sorted data.
  • pageStart of type int - The index of the first row that should be returned to provide the properly paginated data.
  • pageSize of type int - The number of rows that should be returned to provide the properly paginated data.

Note that if you're using Hibernate for loading data there's a simple utility that takes care of all of these parameters, which is described in the Using DataTable with the Hibernate Library. The rest of this section describes how to use these parameters if you need to implement the data providing logic manually.

The filterCriteria variable holds an instance of CompositeFilterCriterion class which has the getCriteria() method that returns a list of filter criterion instances that correspond to the filters and their parameters that are currently specified for the DataTable. Each filter criterion is represented as an instance of ExpressionFilterCriterion class. Each instance of ExpressionFilterCriterion consists of the following:

  • Filter expression string (as specified in the expression attribute of the appropriate filter tag). When using custom data providing, any string can be used as the filter expression and its purpose is to distinguish between the filters. Can be retrieved with the getExpressionStr() method.
  • Filter condition that defines the way that incoming data objects are expected to be compared with the filter argument(s). Can be retrieved with the getCondition() method that returns a condition as a FilterCondition enumeration value.
  • The inverse property that goes in conjunction with the condition property and a value of true means that the condition should be inverted. For example when condition has a value of FilterCondition.EQUALS and inverse is true, the filter is expected to accept only the values that don't match the filter's argument.
  • Filter argument(s) that are selected in the appropriate table's filter. Can be retrieved with the getArg1() and getArg2() methods. The number of arguments available for a particular filter criterion depends on the filter condition. For example, the filter condition of FilterCondition.EQUALS, or FilterCondition.GREATER requires just one parameter, the FilterCondition.BETWEEN requires two parameters, and FilterCondition.EMPTY doesn't require parameters at all.

Here is an example of how these variables can be used in the backing bean:

public List getPreparedCollection() {
    CompositeFilterCriterion filterCriteria = Faces.var("filterCriteria", CompositeFilterCriterion.class);
    String sortColumnId   = Faces.var("sortColumnId", String.class);
    boolean sortAscending = Faces.var("sortAscending", Boolean.class);
    int pageStart = Faces.var("pageStart", Integer.class);
    int pageSize  = Faces.var("pageSize", Integer.class);
    return queryDatabase(filterCriteria, sortColumnId, sortAscending, pageStart, pageSize);
  }

Note that you can use the org.openfaces.util.Faces.var(String varName) method to simplify retrieval of the request-scope variables.

The function that provides the row data for the value attribute must perform the following actions over the original dataset in the following order:

  1. The original dataset should first be filtered according to the filterCriteria variable.
  2. The filtered dataset must be sorted according to the sortColumnId and sortAscending variables.
  3. A sublist of the sorted dataset must be taken starting from a zero-based index specified with the pageStart variable. The size of this sublist is defined by the pageSize variable.
  4. This sublist is the result that should be returned as a value for the value attribute.

Normally, all these actions are automatically performed by issuing an appropriate the database query.

In order for custom data providing to work properly, the following attributes must be also defined:
The following attributes are needed only if selection is enabled or the checkbox column (see above) is used:

  • rowKey - Retrieves a row key that must uniquely identify an appropriate row for the current value of the request-scope variable referencing the current row data i.e. all rowKey objects should be serializable and correctly implement the equals and hashCode methods.
  • rowDataByKey - A value-binding expression that should return row data by the rowKey request-scope variable.
  • If the pagination feature is turned on (i.e. the pageSize attribute is specified), totalRowCount of int type should be specified too. It should return the number of rows on all pages according to the current filtering options (taking into account the filterCriteria attribute).
  • options attribute for each DropDownFilter or ComboBoxFilter component specified for this table. It should be a value-binding expression and be bound to a collection of values that is displayed in the list of these filters.

The following example shows the DataTable component with custom data providing enabled.

<o:dataTable var="citiesTable"
             rowKey="#{city.id}"
             value="#{CitiesList.cities}"
             customDataProviding="true"
             totalRowCount="#{CitiesList.rowCount}"
             rowDataByKey="#{CitiesList.rowByKey}"
             pageSize="20">
  <o:column header="Name" sortingExpression="#{city.name}">
    <f:facet name="subHeader">
      <o:inputTextFilter expression="name"/>
    </f:facet>
    <h:outputText value="#{city.name}"/>
  </o:column>
  <o:column header="City" sortingExpression="#{city.population}">
    <f:facet name="subHeader">
      <o:comboBoxFilter expression="population" options="#{CitiesList.ranges}"/>
    </f:facet>
    <h:outputText value="#{city.population}"/>
  </o:column>
</o:dataTable>

Using DataTable with the Hibernate Library

As described in the Handling Large Datasets section above, the DataTable can work in two different modes. By default, when the custom data providing mode is turned off, the DataTable performs the data manipulation functions such as sorting, pagination and filtering itself and application developers are not required to perform any special actions in the data retrieval code, so you just need to retrieve the whole dataset in the usual way. The example below outlines how this might look with Hibernate:

<o:dataTable var="product"
             value="#{MyBean.products}"
             pageSize="10"
             ...
             >
  <o:column>...</o:column>
  <o:column>...</o:column>
  ...
  <f:facet name="below">
    <o:dataTablePaginator id="paginator"/>
  </f:facet>
</o:dataTable>
...

public List getProducts() { Criteria criteria = getHibernateSession().createCriteria(Product.class); return criteria.list(); }

If the DataTable is dealing with a large amount of data, and has an attached paginator component that allows viewing the data in portions, it's quite easy to make the custom data providing mode to work with Hibernate using the the HibernateCriterionBuilder utility class. The custom data providing mode can be turned on by specifying the customDataProviding attribute with a value of true. This makes the DataTable to skip the built-in logic for sorting, filtering and pagination and delegate this functionality to the data providing method – a method that is bound to the DataTable's value attribute. This method should use the request-scope variables, which are passed by the DataTable to specify the current sorting, filtering and pagination parameters, and return the properly prepared data. You can see the detailed description of these parameters in the Handling Large Datasets section, though there's a set of static utility functions in the HibernateCriterionBuilder class which does the job of retrieving these parameters and constructing the hibernate Criteria object appropriately.

There's a set of buildCriteria functions and the fillCriteria(Criteria) function. The buildCriteria functions can be used to create the new Criteria instance and they accept the Session and the list of parameters identical to that of the Session's createCriteria method family. The fillCriteria(Criteria) function can alternatively be used if you are creating the Criteria object manually and just need to configure it according to the DataTable's custom data providing parameters.

You can use the received Criteria instance as is or perform some additional configurations such as adding application-specific criterion objects or adding aliases before loading the data. Here's a simple example that demonstrates using the custom data providing mode with the buildCriteria method.

<o:dataTable var="product"
             value="#{MyBean.products}"
             pageSize="10"
         customDataProviding=<span class="code-quote">"<span class="code-keyword">true</span>"</span>
         totalRowCount=<span class="code-quote">"#{MyBean.productCount}"</span>
          ...&gt;

<o:column id="name">...</o:column> <o:column id="price">...</o:column> ... </o:dataTable> ...

public List getProducts() { Session session = getHibernateSession(); Criteria criteria = HibernateCriterionBuilder.buildCriteria(session, Product.class); return criteria.list(); } public int getProductCount() { Session session = getHibernateSession(); return HibernateCriterionBuilder.getRowCount(session, Product.class); }

Note that there are some additional requirements:

  • As you can see the example above has the id attribute specified for the column tags. When using the buildCriteria or filterCriteria functions, the id attribute must be specified with the corresponding property names for sorting criteria to be configured properly, or more formally, the value of the id attribute will be passed to the Order.asc(String propertyName) and Order.desc(String propertyName) methods when populating the Criteria object.
  • The totalRowCount attribute that is required when using the custom data providing mode should use another utility function of the HibernateCriterionBuilder class: the getRowCount function returns the number of rows on all pages of the DataTable (which is required for DataTable to calculate the number of pages). Like the buildCriteria/fillCriteria methods, there are several getRowCount methods and can choose the one that is most appropriate for your case.

Fetching Data on DataTable Rendering

When the DataTable component is rendered after a POST request, that is when submitting a form, the data is fetched two times from the data source. This behavior is the same as for the standard <h:dataTable> component – one fetch is for processing the submitted data, and another one is for rendering the new data. However OpenFaces optimizes this behavior when possible, and the data is fetched only once for the display-only DataTables. The display-only mode means that there are no components that implement EditableValueHolder, ActionSource classes (such as <h:inputText> or <h:commandButton> components) and the check-box column and selection features are disabled. If the DataTable is not in display-only mode, the data is fetched twice just like in the standard DataTable component.

Inspecting the Displayed Rows

There are several factors that affect the list of items displayed in the table, such as filtering, pagination, and sorting. You can get the list of data objects for the currently displayed rows in two ways:

  • Declare the displayedRowDatas attribute in your <o:dataTable> tag as a value binding that refers to a property of a list, set or array type. Note that the specified property will never be read by the DataTable, and will only be written to.
  • Use the getDisplayedrowDatas() object of DataTable class if you'd like to use a programmatic approach. Note that you can use the Faces.component("dataTableClientId", DataTable.class) utility function in your backing bean to retrieve a reference to your DataTable.

Inspecting Table's Content

Besides retrieving the list of the currently displayed rows, there are more general means of inspecting table's content. These are the following methods of the DataTable class:

  • getRowCount(DataScope scope) – returns the number of rows within a given scope (see below).
  • getRowDatas(DataScope scope) – returns the row data objects within a given scope.
  • extractTableData(DataScope scope) – returns a TableData object, which contains the major information about the data displayed by the table (in the specified data scope). This information contains a list of columns with their types and headers, the list of rows with their row data objects, and the list of cell data objects and displayed cell strings for each row.

The DataScope enumeration is declared in the AbstractTable class, and it can take the following values that define the scope of data that should be inspected:

  • DISPLAYED_ROWS – corresponds to the rows that are currently displayed in the table, taking into account sorting, filtering and pagination options.
  • FILTERED_ROWS – corresponds to rows on all table's pages (if pagination is enabled). The sorting and filtering options still affect the list of rows. If pagination is not used then this scope is the same as DISPLAYED_ROWS.

Exporting Table's Data

Table data can be exported using the following methods of the DataTable class:

  • export(DataScope scope, TableExporter exporter) – exports the specified table data scope (see the Inspecting Table's Content section above), to a format which is determined by the specified exporter. Exported file name is derived from the table's id.
  • export(DataScope scope, TableExporter exporter, String fileName) – similar to the previous method, but you can specify a file name to which the exported data will be saved explicitly.

In both methods, the exporter parameter specifies the format for the exported file. For now there's only one implementation, which exports data into the comma-separated values format (.csv file): CSVTableExporter. Just create an instance of this class with a no-arg constructor and pass it to the export function. You can also implement your own exporters by extending the TableExporter class and implementing its abstract methods, and particularly the writeFileContent method.

Here's an example of using this feature:

<o:dataTable id="banks" ...>
  <o:column ...>
  <o:column ...>
</o:dataTable>

<o:commandButton value="Export" action="#{Banks.export}"/>

The export method in the Banks backing bean is declared as follows:

public void export() {
  Faces.component("form:banks", DataTable.class).export(
          AbstractTable.DataScope.DISPLAYED_ROWS,
          new CSVTableExporter());
}

Clicking the "Export" button will save the current table's records into the "banks.csv" file, according to the id of the table component, and you can also optionally specify the file name explicitly. Note that if the table has a pagination feature and you'd like to export data for all pages instead of just the current one, then you should use the AbstractTable.DataScope.FILTERED_ROWS parameter instead.

The DataTable export functionality cannot be used on a grouped DataTable (the one whose Row Grouping feature is currently in use).

Keyboard Navigation

The DataTable component supports keyboard navigation both for selection and pagination features. To enable the keyboard support for single selection mode, use the keyboardSupport attribute for <o:singleRowSelection>, and for the multiple selection, use the same keyboardSupport attribute for <o:multipleRowSelection>. Keyboard-enabled pagination between records of the DataTable component is controlled by the paginationKeyboardSupport attribute of the <o:dataTable> tag. By default, all these attributes are set to "true".

By default, if pagination or selection are not enabled, and therefore there's nothing to control from the keyboard, the DataTable component is not focusable. However, if either pagination or selection is provided and the keyboard support for them is turned on, the DataTable component automatically becomes focusable. So you can either use the Tab key or click anywhere inside the DataTable component to focus it.

You can customize the appearance of the focused DataTable component by using the focusedStyle and focusedClass attributes.

The following keyboard keys are available for single row selection in the DataTable component:

MS Windows/Linux Mac OS Action
Up Arrow Up Arrow Move selection one row up from the current one.
Down Arrow Down Arrow Move selection one row down from the current one.
Home Select the first currently visible row.
End Select the last currently visible row.

The user can select multiple rows by moving between rows with the Shift key pressed. Note that only contiguous row ranges can be selected with the keyboard. In addition, the user can select non-contiguous ranges by Ctrl-clicking them.

To move between DataTable pages, the user can use the following keys and key combinations:

MS Windows/Linux Mac OS Action
Ctrl+Home N/A Go to the first page.
Ctrl+End N/A Go to the last page.
Page Up Go to the next page.
Page Down Go to the previous page.

Just like for the standard focusable components you can specify the tabindex attribute for the <o:dataTable> tag to control the input focus order.

Customizing Individual Rows and Cells

In addition to an ability to customize all rows in the DataTable's body at the same time, there is an ability to customize individual rows and cells based on displayed data or any other condition using the <o:row> and <o:cell> tags.

The <o:row> and <o:cell> tags are used to specify content, style or client-side events for specific rows and cells, respectively. In addition, you can merge several cells in a row using the <o:cell> tag (this feature is also known as a colspan feature).

To customize the individual rows, you should add the <o:row> tag as a child of the <o:dataTable> tag. There is a possibility to customize styles and client-side events for the rows that meet the criterion specified in the condition attribute of the <o:row> tag. The condition attribute should be specified as an expression that uses the request-scope variables those refer to the current row. The expression specified in the condition attribute should return a boolean value. The default value is true, which means that if the condition attribute is omitted then the appropriate attributes and child components of the <o:row> tag will be applied to all data rows.

The following example demonstrates making text in all odd rows green:

<o:dataTable var="product"
             value="#{ProductsList.products}"
             rowIndexVar="rowIndex">
   <o:row condition="#{rowIndex % 2 == 0}" style="color: green;"/>
  ...
</o:dataTable>

It is also possible to customize cells and their contents in the appropriate rows. This can be done by placing the <o:cell> tags as child tags for the Row component as described below.


The individual cells can be customized by adding the <o:cell> tags as children of the <o:row> tag. There are two ways of specifying <o:cell> tags within a row, which differs in a way how cell customizations are applied to columns within a row. The first one is creating a list of so called free cells (<o:cell> tags without columnIds or condition attributes), which results in customizing cells one-by-one starting from the first column. The second one is explicitly binding cells to some specific columns within the row using the columnIds or condition attributes of <o:cell> tags. The first approach (with a list of free cells) is most appropriate if you'd like to override declarations for all cells in a row, and the second one is good if you need to customize just one or a few cells, and retain the rest of the row's cells intact.

Regardless of the way that <o:cell> tags are bound to columns within a row, each <o:cell> tag has the following possibilities for cell customization. The style and styleClass attributes can be used to customize a style for the appropriate cells (see Conditional Styles section). There are also attributes for customizing cell's client-side events (see Specifying User Events section). The <o:cell> tags may have no content if you just need to customize cell's styles or events. But it is also possible to customize cell's contents that should be displayed instead of the default cell contents. This can be done by placing child components inside of <o:cell> tag. These components just like ordinary components inside of <o:column> tags can use the request-scope variables referring to the current row.

You can specify one or more of free cells, up to the number of columns declared in the table. Free cells are applied to the appropriate columns in the order that columns are declared on the page. The example below shows customizing the first two cells of each row that satisifies a simple criterion.

<o:dataTable var="product"
             value="#{ProductsList.products}">
  <o:row condition="#{product.number == 0}">
    <o:cell style="background-color: red;"/>
    <o:cell>
      <h:outputText value="Not available" style="color: red;"/>
    </o:cell>
  </o:row>
  ...
  <o:column>...</o:column>
  <o:column>...</o:column>
  ...
</o:dataTable>

In addition, or as an alternative to specifying free cells, you can also specify any number of explicitly-bound cells. You can either use columnIds attribute, or condition attribute in <o:cell> tags to specify explicitly-bound cells. Note that unlike using free cells, using these attributes you can optionally make a single <o:cell> declaration to be applied to more than one column in the same row.

If you need to assign the Cell component to some specific column(s) you can do so by declaring the columnIds attribute of the <o:cell> tag. This attribute allows specifying identifiers of the columns in which the cells are to be customized. The column identifiers should be separated by a comma. You can also specify the columnIds attribute as a value-binding expression. In this case, you should bind this attribute to an array or a collection of java.lang.String class instances.

The following example demonstrates the Cell components assigned to the columns by identifiers:

<o:dataTable var="product"
             value="#{ProductsList.products}">
  <o:row condition="#{product.number == 0}">
    <o:cell columnIds="productName,productNubmer" style="color: red;"/>
  </o:row>
  ...
  <o:column id="productName">...</o:column>
  ...
  <o:column id="productNumber">...</o:column>
  ...
</o:dataTable>

Another possibility to specify explicitly-bound cells is specifying a condition that defines columns in which the cells are to be customized. To do so you should use the condition attribute. This attribute should be specified as a value-binding expression that returns a boolean value based on the request-scope variables referring to the current cell. Returning true means that the <o:cell> tag will be applicable to a cell determined by the given set of request-scope variables.

Here is an example of assigning the cells to the columns using a condition. It shows making a silver background for all cells in odd columns:

<o:dataTable var="product"
             columnIndexVar="columnIndex"
             value="#{ProductsList.products}">
  <o:row>
    <o:cell condition="#{columnIndex % 2 == 0}" style="background: silver;"/>
  </o:row>
  ...
</o:dataTable>
Please note that the columnIds and condition attributes are mutually exclusive.

It is also possible to specify both free cells and explicitly-bound cells inside of the same <o:row> tag. Just place free cells first, and explicitly-bound ones afterwards. If several <o:cell> declarations will be applicable to the same displayed cell then the styles and events from all applicable cell declarations will be applied to the same displayed cell.

You can mix the <o:cell> tags with the columnIds or condition attributes and without these attributes specified within one row. In this case the cells without the columnIds or condition attributes are applied first regardless of the order of the tag declaration.

Support for Merging Row Cells

The OpenFaces DataTable also provides an ability to merge several cells inside of a single row. To merge several cells within one row, you should specify the span attribute of the <o:cell> tag. The span is an integer attribute that is set to 1 by default. This attribute defines a number of cells to the right of this cell (including this cell itself) that should be merged with this cell, so a value of 1 means that no cells are "attached" to this one.

Note that the span attribute is just an additional possibility of the <o:cell> tag, and it can be used in combination with all other customization possibilities provied by this tag.

Below is an example with a table consisting of three columns. The cells in the second row are merged across all three columns and contain the custom content text displayed using the <h:outputText> component:

<o:dataTable var="product"
             value="#{ProductsList.products}">
  <o:row condition="#{rowIndex == 1}">
    <o:cell span="3">
      <h:outputText value="Merged cell contents"/>
    </o:cell>
  </o:row>
  ...
  <o:column>...</o:column>
  <o:column>...</o:column>
  <o:column>...</o:column>
  ...
</o:dataTable>

Please note that when the cells are merged, the content, styles and events from the first of the merged cells are used. Content, styles and events from the other merged cells are ignored.

Customizing Styles

Section Styles

By default, the DataTable component uses a default style. To turn it off, set the applyDefaultStyle attribute to "false".

Like the HTML <table> tag, <o:dataTable> supports the align, bgcolor, dir, rules, width, border, cellspacing, and cellpadding attributes. Also, the <o:column>, <o:selectionColumn> and <o:checkboxColumn> tags have width, align and valign attributes that are rendered onto the <col> tag of the respective column.

The DataTable component provides a number of style attributes for customizing the appearance of its header, body, and footer.

 Parts of 
 DataTable 
 Style attributes 
 Class attributes 
    Example legend    
Entire table style styleClass
Table header headerSectionStyle headerSectionClass
Table body bodySectionStyle bodySectionClass
Table footer footerSectionStyle footerSectionClass

The appearance of the DataTable component in the rollover state is defined by the rolloverStyle and rolloverClass attributes.

Row Styles

The DataTable component allows you to specify style information for the rows that span the header and footer of the component or its individual columns. All style attributes are listed in the table below:

Types of rows
 Style attributes 
 Class attributes 
 Example legend 
Table header row commonHeaderRowStyle commonHeaderRowClass
Column header row headerRowStyle headerRowClass
Sub-header row subHeaderRowStyle subHeaderRowClass
Body rows bodyRowStyle bodyRowClass  
Body odd rows, if different from the body row style bodyOddRowStyle bodyOddRowClass  
Body rows in the rollover state rolloverRowStyle rolloverRowClass  
Column footer row footerRowStyle footerRowClassv
Table footer row commonFooterRowStyle commonFooterRowClass
NOTE that although row style attribute declarations, and other DataTable styling attributes, specify the way that appropriate parts of DataTable component will look from the user's standpoint, the developers shouldn't rely on how the appropriate CSS classes are applied to the HTML tags generated by the DataTable component, unless this is mentioned in documentation explicitly.
            <p>In particular you cannot rely on the fact that CSS classes specified with <b>bodyRowClass</b>
                attribute are applied to the <tt>&lt;tr&gt;</tt> tags of the generated HTML code, as they can for
                example be applied to the appropriate <tt>&lt;td&gt;</tt> tags, to make style declarations look as
                uniform as possible across different browsers, different rendering modes, etc.</p>
Styles Example

The following example shows the styles applied to the DataTable sections and its header and footer rows:

<o:dataTable pageSize="5" var="person"
             value="#{PeopleList.person}"
             rolloverRowStyle="background:#F0F0F0"
             headerSectionStyle="font-size:13pt; color:#2e343d;"
             bodySectionStyle="background-color:#fef9ee; color:#106574"
             footerSectionStyle="font-size:13pt; color:#223957"
             headerRowStyle="background-color:#e1caa2"
             footerRowStyle="background-color:#aabede"
             commonHeaderRowStyle="background-color:#aec2c5"
             commonFooterRowStyle="background-color:#769ecb"
             subHeaderRowStyle="background-color:#faefd2">
  ...
</o:dataTable>

And here is the result:

Column Styles

You can apply styles to any type of a DataTable column: <o:column>, <o:selectionColumn>, and <o:checkboxColumn>. The following table lists all style attributes for the column tags:

Parts of the column Style attributes Class attributes
Entire column style styleClass
Column header headerStyle headerClass
Column filter cell filterCellStyle filterCellClass
Column body bodyStyle bodyClass
Column footer footerStyle footerClass

The <o:columns> tag also supports all above mentioned attributes. These attributes can be specified as value-binding expressions that use a column data variable specified in the var attribute of the <o:columns> tag.

In addition, all of the above attributes, except filterCellStyle and filterCellClass can be specified for the <o:columnGroup> tag. Header and footer style attributes are applied to the group's header and footer cells respectively, and general column style and column body styles are applied to the respective parts of each column inside of the group.

Gridline Styles

With the DataTable component, you can define styles for gridlines and separators. Each of them has its own attribute given in the table below:

Type of separators Attribute
Horizontal lines in the DataTable body. horizontalGridLines
Vertical lines in the DataTable body. verticalGridLines
A line that separates the table header from the rest of the table. commonHeaderSeparator
A line that separates the table footer from the rest of the table. commonFooterSeparator
A line that separates the header section from the body section. headerHorizSeparator
A line that separates the column headers row and the sub-header row. subHeaderRowSeparator
A line that separates the footer section from the body section. footerHorizSeparator
Vertical lines between column headers. headerVertSeparator
Vertical lines between column footers. footerVertSeparator


You should specify all separator-related style attributes in the same way as the CSS border property but without the prefix "border:".


The following example shows styles applied to the gridlines of the DataTable component:

<o:dataTable var="product" value="#{ProductsList.products}"
             horizontalGridLines="1px dotted gray"
             verticalGridLines="1px dotted gray"
             commonHeaderSeparator="3px solid gray"
             commonFooterSeparator="3px solid gray"
             headerHorizSeparator="2px solid gray"
             subHeaderRowSeparator="1px dotted black"
             footerHorizSeparator="2px solid gray"
             headerVertSeparator="1px solid gray"
             footerVertSeparator="1px solid gray">
  ...
</o:dataTable>

And here is the result:

If the DataTable component displays any gridlines or separators, the border, rules, and cellSpacing attributes of the <o:dataTable> take no effect.
Column Group Separators

The previous section describes the way that gridlines can be customized in a table without grouped columns, though there are some additional customization possibilities when a table contains column groups:

  • Specifying different styles for separators between ordinary columns and column groups. This can be done by specifying a list of comma-separated gridline styles in the verticalGridLines, headerVertSeparator and footerVertSeparator attributes, for example as follows: "1px solid silver, 2px solid silver". This will make the first style in the list to be used for ordinary column separators, and the second style in the list to be used for column group separators. Actually, the list of styles is not restricted to two items – you can specify any number of styles in this attribute, which can be required in case of deeper column hierarchies when there are groups that contain other column groups. The default value for the verticalGridLines attribute is "none, 1px solid #e0e0e0", which means that there are no separators between the ordinary columns, and there are light-grey separators between column groups.
  • Customizing horizontal separators between multiple header and footer rows that are created as a result of displaying several levels of columns and column groups. Similarly to customizing the vertical grid lines, this can be done by specifying one or more gridline styles in the multiHeaderSeparator and multiFooterSeparator attributes. The default value for these attributes is "none, 1px solid #a0a0a0", which means that there is no horizontal separator betwen first-level column group header and headers of its sub-columns, but if there is a more deep hierarchy of column groups then headers of the higher-level group headers will be separated with a gray line.
Conditional Styles

While all of the styles described above are applied to appropriate areas of the DataTable component regardless of the data displayed in them, there is an ability to customize a style for individual rows or cells based on displayed data or any other condition using style and styleClass attributes of the <o:row> and <o:cell> tags, respectively. Specifying conditional styles are only a part of capabilities provided by these tags.

Here's an example of applying style to some individual rows and cells.

<o:dataTable var="item" rowIndexVar="rowIndex" columnIndexVar="colIndex" ...>
  <o:row condition="#{item.important}" style="font-weight: bold"/>
  <o:row>
    <o:cell columnIds="itemColor" style="color: #{item.color}"/>
  <o:row>
  <o:row condition="#{rowIndex==5}">
    <o:cell condition="#{colIndex==2}" styleClass="cell5x2"/>
  <o:row>

<o:column id="itemColor">...</o:column> ... </o:dataTable>

Note that <o:cell> tags should be nested within the <o:row> tags. The three <o:row> declarations in this example introduce three rules for styling individual rows:

  • the first one emphasizes items having their "important" attribute equal to true with a bold text
  • the second declaration is applicable for all rows (there's no condition for that tag), and it specifies an individual color for all cells in the "itemColor" column, based on the value stored in each respective item.
  • the third declaration combines specifying condition for <o:row> and <o:cell> tags, which results in applying the specifying CSS class to the cells that meet both conditions.

Note that there are more scenarios of using the <o:row> and <o:cell> tags, for example it's possible to customize several cells within a single <o:row> declaration or customize cell content and events in addition to styling them. Refer to the Customizing Individual Rows and Cells section for the full information.

Style Hierarchy

Because of the variety of ways to style different parts of the DataTable component, some style definitions may overlap. To avoid any style conflict, please keep in mind that cell styles have the highest priority, followed by row styles, column styles, section styles, and finally DataTable styles having the lowest priority.

Since there are several styling attributes for most of the mentioned groups (row styles, column styles, etc.), each group defines its own list of in-group priorities (listed from higher to lower below):

  • Row styles: style for selection, rolloverRowStyle, conditional row styles, bodyOddRowStyle, bodyRowStyle
  • Column styles: headerStyle/bodyStyle/footerStyle, style
  • DataTable styles: focusedStyle, rolloverStyle, style

Note that these in-group priorities are only applicable when styles are specified with *Style tags. Specifying the in-group priorities using the *Class tags are subject to the standard CSS cascading rules, which means that the order of CSS declarations is taken into account. The CSS classes declared later on a page take precedence over the ones declared earlier. This can be important for conflicting style declarations. For example let's consider a table whose bodyRowClass attribute and the styleClass attribute in the <o:singleRowSelection> tag both have different "background-color" declarations in the respective classes. In order for selection to be visible in this case, the body row class declaration should go before the selection class declaration.

Specifying User Events

The DataTable component supports a set of standard client-side events. You can specify them using the following attributes of the <o:dataTable> tag: onclick, ondblclick, onmousedown, onmouseover, onmousemove, onmouseout, onmouseup, onfocus, onblur, onkeydown, onkeyup, onkeypress.

In addition, you can specify client-side events for any kind of a DataTable column (<o:column>, <o:selectionColumn>, or <o:checkboxColumn> tags), or to a group of columns (�<o:columnGroup> tag). All event-related attributes are listed below:

Part of column Attributes
Entire column onclick, ondblclick, onmousedown, onmouseover, onmousemove, onmouseout, onmouseup
Column header headerOnclick, headerOndblclick, headerOnmousedown, headerOnmouseover, headerOnmousemove, headerOnmouseout, headerOnmouseup
Column body bodyOnclick, bodyOndblclick, bodyOnmousedown, bodyOnmouseover, bodyOnmousemove, bodyOnmouseout, bodyOnmouseup
Column footer footerOnclick, footerOndblclick, footerOnmousedown, footerOnmouseover, footerOnmousemove, footerOnmouseout, footerOnmouseup

In case of column groups, the events declared for the group are applied to each column in the group, except the header and footer events those are applied to the group's header and footer cells respectively.

The <o:columns> tag also supports all above mentioned attributes. These attributes can be specified as value-binding expressions that use a column data variable specified in the var attribute of the <o:columns> tag.

The <o:singleRowSelection> and <o:multipleRowSelection> tags provide the onchange event. You can specify it using the onchange attribute.

You can specify client-side events for the particular row or cell using the following attributes of the <o:row> and <o:cell> tags: onclick, ondblclick, onmousedown, onmouseover, onmousemove, onmouseout, onmouseup, onkeydown, onkeyup, onkeypress. When specify row or cell-specific client-side events, you can use request-scope variables of the DataTable component (see the description of var, rowIndexVar, columnIndexVar and columnIdVar attributes in the section Request-Scope Variables).

Client-Side API

The following table lists all client-side API methods for the DataTable component:

Method Description
selectAllRows() Selects all rows in a table on which this method is invoked. This method works with multiple selection mode only.
clearSelection() Clears selection in a table on which this method is invoked. This method works with any selection mode.
isSelectionEmpty() Returns "true" if the table has any selected rows. This method works with any selection mode.
getSelectedRowIndex() Returns a zero-based index of the current selected row, or "-1" if there is no selected row. The table must be in single selection mode.
setSelectedRowIndex(rowIndex) Selects a row with the index specified in the rowIndex parameter. The table must be in single selection mode.
getSelectedRowIndexes() Returns an array of zero-based indexes of the current selected rows. The table must be in multiple selection mode.
setSelectedRowIndexes(rowIndexes) Selects rows with indexes that are passed in the rowIndexes array. The table must be in multiple selection mode.
getSelectedRowKey() Returns a row key of the current selected row, or null if there is no selected row. The table must be in single selection mode.
setSelectedRowKey(rowKey) Selects a row with the row key specified in the rowKey parameter. The table must be in single selection mode.
getSelectedRowKeys() Returns an array of row key values of the current selected rows. The table must be in multiple selection mode.
setSelectedRowKeys(rowKeys) Selects rows with row key values that are passed in the rowKeys array. The table must be in multiple selection mode.
getSelectedCellId() Returns a cellId of current selected cell. The table must be in single selection mode.
setSelectedCellId(cellId) Selects a cell with specified rowIndex and columnId in the cellId parameter. The table must be in single selection mode.
getSelectedCellIds() Returns an array of cellIds of the current selected cells. The table must be in multiple selection mode.
setSelectedCellIds(cellIds) Selects cells with specified rowIndex and columnId values that are passed in the cellIds array. The table must be in multiple selection mode.
getRowCount() Returns the number of rows currently visible in the table.
getCurrentColumn() Returns the object identifying the column for which the column context menu is currently being shown (see the Displaying Column Menus section). This object currently has only one field named index, which is a zero-based index of the column in a list of currently-rendered columns.
focus() Gives the keyboard focus to the DataTable component on which this method is invoked.
blur() Removes the keyboard focus from the DataTable component on which this method is invoked.
Client-Side Row Keys

As you can see in the section above, there are several client-side API methods which receive or return row key values. These are the client-side row key values, which are used to uniquely identify rows and are often more convenient for referring to rows than row indexes. Row index just specifies where the row resides visually in the list of displayed records, and index of the same data row can be different depending on sorting and filtering options, which can be a problem for certain applications, and row keys can solve this problem.

These client-side row key values are calculated for each row by converting the respective server-side row key values to string by invoking their toString() method. See the Model Row Objects Requirements section to see how server-side row keys should be specified. Note that if the rowKey attribute of <o:dataTable> tag is not specified, then row data object is assumed to be the row key object, and its string representation as calculated the toString() method will serve as client-side row key.

Limitations

  • The DataTable component cannot be used inside DataTable, TreeTable or any other JSF components that replicate their child components during rendering.
  • Dynamic columns cannot have filters.
  • OpenFaces components and the components that extend UIInput and UICommand cannot be used in the <o:cell> tag if this cell is rendered several columns per row.
  • Resources from the <f:loadBundle> tag cannot be used inside Ajax-enabled components. Though this can easily be solved by using the <o:loadBundle> component. See the LoadBundle documentation.
  • Component binding of DataTable and Column components cannot be used for session-scope bean
  • The <o:summaries> tag described in the Table-Wide Customization API section does not work with Mojarra 2.0.3 and works only in Mojarra 2.1.11. If you have to use the summary calculation functionality with Mojarra 2.0.3, you can use the <o:summary> tags instead, as described in the Fine Customization API for this.
Clone this wiki locally