DataTable

The DataTable component is used to display data in a tabular format and effectively manipulate it. It supports all the features of the standard JSF HtmlDataTable component and, in addition, provides a number of its own.


API Reference | Tag Reference
Online Demo

Key Features

Specifying the Content

To add the DataTable component to a page, use the <q: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 <q:dataTable> tag.

The DataTable component supports several column types: <q:column>, <q:checkboxColumn> and <q:selectionColumn> (for more information, see the section Specifying Columns below). In addition you can specify dynamic number of columns using the <q: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 <q: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 <q: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 <q:row>, <q:cell>, <q:rowStyle> and <q:cellStyle> tags.

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 <q:cell> and <q:cellStyle> tags:

  • 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 getRequestMapValue() method to retrieve a request-scope variable by its name.

Model Row Objects Requirements

In order for the DataTable's features to work properly, additional requirements are imposed on specifying the table data source. To store selected rows between requests, one of the following conditions should be met:

  • All row data instances provided by the value attribute should be serializable and correctly implement the equals and hashCode methods.
  • The rowKey attribute should be specified. This attribute retrieves a row key that must uniquely identify an appropriate row and satisfy the previously mentioned requirements. Note that rowKey attribute binding should not return a null value.
<q:dataTable var="product"
             value="#{ProductsList.products}"
             rowKey="#{product.id}">
  ...
</q:dataTable>

If row data does not meet the requirements and the rowKey attribute is not defined, the table generates row keys based on row indexes. As a result, the features that require a row key may work improperly. For example, if some row is selected and the user changes the sort order, a different row with the same row index gets selected, and this may be the row with different data.

Specifying Columns

The list of DataTable's columns is specified using the <q:column> child tags. Columns are used to split each row provided by the value attribute into cells. Child components of the <q: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 <q:column>, the DataTable component supports also two types of columns:

  • <q: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).
  • <q: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" and "footer" facets which you can use to specify the table header and footer.

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.

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

Specifying Dynamic Columns

In addition to column types listed in section Specifying Columns the QuipuKit DataTable provides an ability to specify dynamic number of columns. To add dynamic columns to the DataTable, use the <q:columns> child tag of the <q:dataTable> tag.

The list of the dynamic columns is specified using the value attribute. 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 <q: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 Columns.

Most of the attributes of <q:columns> tag are analogous to their counterparts in the <q: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 <q:columns> tag. When specifying child components of the <q:columns> tag, the request-scope variables declared in the var and rowIndexVar attributes of the <q:dataTable> tag can be used. In addition you can refer to the curent column when specifying child components of the <q:columns> tag using the column data request scope variable.

The <q: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 <q: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 <q:columns> tag are used in the same way as id attributes of ordinary <q: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 <q:columns> tag:

<q:dataTable value="#{tableBean.tableValue}"
             var="row">
<q:columns value="#{tableBean.dynamicColumns}"
           var="col"
           columnId="dynamicCol#{col}"
           columnRendered="#{tableBean.columnRendered}">
    <f:facet name="header">
        <h:outputText value="#{col}"/>
    </f:facet>
    <h:outputText value="#{row.dynamicColumns[col]}"/>
</q:columns>
</q:dataTable>

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

Grouping Columns

It is possible to combine columns into groups to reflect their logical connections. This can be done by enclosing several column tags into the <q: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:

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

Note that there are both the columns that are enclosed into <q: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.

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

Column Resizing

It is possible to let the user resize columns by adding the <q:columnResizing> tag as a child of <q: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 <q: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:

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

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

Note
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 <q:columnResizing> tag.

Column width changes made by the user can be persistend between different visits of the appropriate page using the <q:columnResizing> tag's resizingState attribute. This attribute can be bound to a backing bean property having the ColumnResizingState type. This property will be written to save the current column widths when the table is submitted, and will be read when the table is rendered next time.

Concurrent Data Modifications

The DataTable component allows you to insert any editable components in its cells, for example HTMLInputText, HTMLSelectManyCheckBox, HTMLSelectOneListBox, 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.

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 <q: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 <q: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).

<q: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>
</q: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.

<q: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>...
</q:dataTable>

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:

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

Dynamic columns support sorting as well. Just like ordinary columns, dynamic columns can be made sortable by specifying the sortingEnabled attribute in <q: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 <q: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 <q: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:

<q:dataTable value="#{tableBean.tableValue}"
             var="row">
<q: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]}"/>
</q:columns>
</q: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:

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

When the DataTable component is loaded for the first time, the data are rendered unsorted. You can specify which column should be sorted on page load and in what order 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.

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".

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 <q: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.

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 <q: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.

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

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

Filtering

The DataTable component allows the user to filter the original set of displayed records. Each column that is configured for filtering has a special component below the column header that lets the user enter or select a value (called "filter value") based on which the records in that column get filtered. When a filter value is specified, only the records that match this value are displayed. If a filter value is specified for more than one column, only the records that satisfy all of the specified filter criteria are displayed.

To provide filtering for a column, you should first specify the filterExpression attribute for the <q:column> tag. This attribute must be a value-binding expression that specifies the value by which data will be filtered. The expression can address the current row object by the var request-scope variable.

A row is considered accepted by the filter if a user-entered value is either a substring of text returned by filterExpression for that row or an exact match of that text, depending on the filter component type (see below). If the filterExpression attribute doesn't specify a string, the toString() method is invoked on the returned object to obtain a string for filtering. If filterExpression returns null or an empty string, this value is considered empty by the predefined filter values (described below).

The DataTable component provides several filter components for filtering its data. To specify the type of a filter component, set the filterKind attribute to one of the following values:

  • "searchField" (default). Displayed as a text field. User-entered text will be searched as a substring in a case-insensitive manner.
  • "comboBox". Displayed as a combo box containing all the unique values returned by the filterExpression attribute for that column. Records are filtered by an exact string match.
  • "dropDownField". Displayed as a drop-down field which, like the "comboBox" filter, displays all the unique values and, in addition, allows text entry. Records are filtered by a substring in a case-insensitive manner.

The following figure shows three types of filter components: "dropDownField" for the first column, "comboBox" for the second, and "searchField" for the third.

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 the "comboBox" filter).
  • "<Non-empty> - Displays all records with non-empty values (only for the "comboBox" filter).

You can change the text of the predefined filter values in the "comboBox" or "dropDownField" filters by using the allRecordsFilterName, emptyRecordsFilterName and nonEmptyRecordsFilterName attributes of the <q:dataTable> tag. To specify explicitly the filter values that will appear in the "comboBox" or "dropDownField" filters instead of all possible values, use the filterValues attribute of the <q:column> tag. If no records satisfy filter criteria, an appropriate message will be displayed (see the section Displaying a Message for Empty Data above).

The following example demonstrates the filtering feature. A drop-down field is used to filter products by name:

<q:dataTable var="product"
             value="#{ProductsList.products}" >
  <q:column filterExpression="#{product.name}"
            filterKind="dropDownField">
    <f:facet name="header">
      <h:outputText value="name"/>
    </f:facet>
    <h:outputText value="#{product.name}" />
  </q:column>
</q:dataTable>

You can use the filterValues attribute of the <q:column> tag to define a list of items displayed in the "comboBox" or "dropDownField" filters. For example, if you need to retrieve a list of filter values in the order you want. It should be a value-binding expression and be bound to a collection of values that is displayed in the list of the "comboBox" or "dropDownField" filter components.

You can also define the current filter value by using the filterValue attribute of the <q:column> tag. This attribute can be bound to an instance of the teamdev.jsf.component.datatable.FilterCriterion class. Note that this is a base abstract class and the actual values that this attribute can take are instances of its subclasses. There are three such classes, which are applicable to various type of selections in various types of filters: TextFilterCriterion, EmptyRecordsCriterion, and NonEmptyRecordsCriterion. An instance of the TextFilterCriterion class specifies a text by which the cells in the appropriate column should be filtered. This is the only class that is applicable to columns with the "searchField" and "dropDownField" filter type. The columns with the "comboBox" filter type, can have filterValue values of all three classes: TextFilterCriterion, EmptyRecordsCriterion, and NonEmptyRecordsCriterion.

The following example demonstrates the usage of the filterValues and filterValue attributes:

<q:dataTable var="product"
             value="#{ProductsList.products}" >
  <q:column filterExpression="#{ProductsList.productPriceRange}"
            filterKind="dropDownField"
            filterValues="#{ProductsList.priceRanges}"
            filterValue="#{ProductsList.selectedPriceRange}">
    <f:facet name="header">
      <h:outputText value="price"/>
    </f:facet>
    <h:outputText value="#{product.price}" />
  </q:column>
</q:dataTable>

Dynamic columns can be made filterable as well. The <q:columns> tag supports all above mentioned attributes and they have the same meaning. The main difference is that all these attributes (except of filterKind for which it's optional) must be specified as value-binding expressions where you can use a column data variable specified in the var attribute of the <q:columns> tag.

Just like ordinary columns, dynamic columns can be made filterable by specifying the filterExpression attribute. This attribute must be specified as a value-binding expression that should reference the value by which the data in each dynamic column is filtered. The filterKind attribute can optionally be specified whether on the page or as a value-binding expression referencing the type of filter component for filtering the data in dynamic columns. If the filterKind attribute returns null the corresponding dynamic columns become non-filterable.

The meaning of the filterValues and filterValue attributes is the same as in <q:column> tag. Note that if the filterValues attribute returns null, the default filter values calculation mechanism is used for the corresponding dynamic columns.

The following example demonstrates the filtering feature for the dynamic columns:

<q:dataTable value="#{tableBean.tableValue}"
             var="row">
<q:columns value="#{tableBean.dynamicColumns}"
           var="col"
           filterExpression="#{row.dynamicColumns[col]}"
           filterKind="dropDownField">
    <f:facet name="header">
        <h:outputText value="#{col}"/>
    </f:facet>
    <h:outputText value="#{row.dynamicColumns[col]}"/>
</q:columns>
</q:dataTable>

You can apply styles to the row that contains a filter component by using the filterRowStyle and filterRowClass attributes. To define a style for the line that separates the row with an embedded filter component and the column header, use the filterRowSeparator attribute.

Note
You should specify the filterRowStyle attribute in the same way as the CSS border property but without the prefix "border:".

For example:

<q:dataTable var="product"
             value="#{ProductsList.products}"
             filterRowStyle="background: gray"
             filterRowSeparator="1px dotted black">
  ...
</q:dataTable>

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.

You can use a JavaScript q_refreshTable(tableId, submittedComponentIds, serverAction) function to reload the DataTable component without reloading the whole page. The DataTable is submitted using this function the same way as in case of standard page submission, i.e. with selection, filtering, pagination parameters, inner components and facets, but without reloading the whole page. Note that you can use this function only for the DataTable component that has its useAjax attribute set to "true".

Components outside of the DataTable component can also be submitted using this function. To do so, you should specify the submittedComponentIds parameter of the q_refreshTable function. In this parameter, specify an array of client IDs for the components that should be submitted along with the DataTable and its inner components. Note that these components are not re-rendered after the Ajax request by using the q_refreshTable function.

You can also specify an action that is executed during the Ajax request using the serverAction parameter of the q_refreshTable function. This parameter should be specified in the "backingBeanName.methodName" form. The method this action refers to should be a public method without parameters and having a "void" return type.

Here is an example of the q_refreshTable function usage :

<h:form id="form1">
    <q:dataTable id="allPeople"
                 var="person"
                 value="#{PeopleList.person}">
      <q:multipleRowSelection rowDatas="#{PeopleList.selectedRows}"/>
      ...
    </q:dataTable>
    <h:commandButton value="Add Selected People"
                     type="button"
                     onclick="q_refreshTable('form1:selectedPeople', ['form1:allPeople'], null); "/>
    <q:dataTable id="selectedPeople"
                 var="selectedPeople"
                 value="#{PeopleList.selectedRows}">
      ...
    </q:dataTable>
  </h:form>

In this example, when the user clicks the Add Selected People button, the "allPeople" DataTable is submitted and in the "selectedPeople" DataTable, selected people from the "allPeople" table are displayed.

See also the Client-Side API section.

Note
The q_refreshTable function reloads the DataTable component asynchronously, i.e. it initiates an Ajax request for reloading the DataTable component and returns without waiting for this request to be completed.

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, refreshing the DataTable with JavaScript. 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>) or HTML tag (such as <div>) with the id attribute specified.

Here is an example:

<q:dataTable ...>
...
<f:facet name="below">
<h:panelGroup id="panelGroup">
  <q:dataTablePaginator/>
  <h:outputText value="#{BackingBean.value}"/>
</h:panelGroup>
</f:facet>
</q: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 don't want to let the user change the selection, set the enabled attribute of the <q:singleRowSelection> or <q: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 <q:singleRowSelection> tag. To detect which row is currently selected or change selection, the <q: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 you want to change selection from the backing bean, the row data object provided by the rowData attribute 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:

<q:dataTable var="product"
             value="#{ProductsList.products}" >
  <q:singleRowSelection
          rowData="#{ProductList.selectedProduct}"/>
  <q:column>
    <f:facet name="header">
      <h:outputText value="name"/>
    </f:facet>
    <h:outputText value="#{product.name}" />
  </q:column>
</q: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 <q: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 <q:singleRowSelection> tag. The use of this attribute is similar to the action attribute of the HTMLCommandButton component. 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.

The following examples shows the usage of the action attribute.

<q:dataTable var="product"
             value="#{ProductsList.products}" >
  <q:singleRowSelection
          rowData="#{ProductList.selectedProduct}"
          action="#{ProductList.processProductSelection}"/>
  <q:column>
    <f:facet name="header">
      <h:outputText value="name"/>
    </f:facet>
    <h:outputText value="#{product.name}" />
  </q:column>
</q: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 <q:singleRowSelection> tag. Both attributes are "true" by default.

To apply a style for a selected row, use the style and styleClass attributes of the <q:singleRowSelection> tag.

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 <q:multipleRowSelection> tag. The only difference between specifying single and multiple selection is that <q: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 if you want to change selection from the backing bean, 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.

<q:dataTable var="product"
             value="#{ProductsList.products}" >
  <q:multipleRowSelection rowDatas="#{ProductList.selectedProducts}"/>
  <q:column>
    <f:facet name="header">
      <h:outputText value="name"/>
    </f:facet>
    <h:outputText value="#{product.name}" />
  </q:column>
</q: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 <q:selectionColumn> tag.

For multiple selection mode, you can add a child <q: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.

<q:dataTable var="product"
             value="#{ProductsList.products}" >
  <q:multipleRowSelection ... />
  <q:selectionColumn>
    <f:facet name="header">
      <q:selectAllCheckbox />
    </f:facet>
  </q:selectionColumn>
  <q:column>
    <f:facet name="header">
      <h:outputText value="name"/>
    </f:facet>
    <h:outputText value="#{product.name}" />
  </q:column>
</q: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 and 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 <q:checkboxColumn> tag. It has two attributes, rowDatas and rowIndexes, which you should define as value-binding expressions that reference a list of row data objects and java.lang.Integer instances, respectively. Please note that the nodePaths attribute is only applicable for the TreeTable component. In addition, you can add a child <q:selectAllCheckbox> tag to the "header" or "footer" facets (or both) of the <q: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 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.

The following example shows the usage of the checkbox column.

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

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 <q: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.

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

  • filterCriteria of List type of FilterCriterion objects - The filtering criteria that is currently selected in the DataTable component. This variable must be processed if filtering is enabled for the DataTable component.
  • sortColumnId of String type - The column ID by which the DataTable component is sorted. This variable is needed to return correctly sorted data.
  • sortAscending of boolean type - The sort order in which the column is sorted. This variable is needed to return correctly sorted data.
  • pageStart of int type - The index of the first row that should be returned.
  • pageSize of int type - The number of rows that should be returned.

The filterCriteria variable represents a list of FilterCriterion objects. FilterCriterion is a base class and each entry in filterCriteria will actually be one of its subclasses:

  • EmptyRecordsCriterion class. An instance of this class represents a filter that should only accept all empty records in the appropriate column. The column is identified by the columnId property.
  • NonEmptyRecordsCriterion class. An instance of this class represents a filter that should only accept all non-empty records in the appropriate column. The column is identified by the columnId property.
  • TextFilterCriterion class. An instance of this class represents a filter that should accept all records satisfying the specified text criterion. The value of that criterion can be retrieved from the text property. The column to which this filter is applied is identified by the columnId property.

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

public List getPreparedCollection() {
    List filterCriteria =
            (List) FacesUtil.getRequestMapValue("filterCriteria");
    String sortColumnId =
            (String) FacesUtil.getRequestMapValue("sortColumnId");
    boolean sortAscending =
            ((Boolean) FacesUtil.getRequestMapValue("sortAscending")).booleanValue();
    int pageStart =
            ((Integer) FacesUtil.getRequestMapValue("pageStart")).intValue();
    int pageSize =
            ((Integer) FacesUtil.getRequestMapValue("pageSize")).intValue();
    return queryDataBase(filterCriteria, sortColumnId, sortAscending, pageStart, pageSize);
  }

Note that you can use the getRequestMapValue() 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 the database by issuing an appropriate query.

In order for custom data providing to work properly, the following attributes must be also defined:

  • filterValues attribute for each column with filtering enabled - should be specified instead of the filterExpression attribute. It should be a value-binding expression and be bound to a collection of values that is displayed in the list of the "comboBox" or "dropDownField" filter components.
    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).

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

<q:dataTable var="product"
             rowKey="#{product.id}"
             value="#{ProductsList.products}"
             customDataProviding="true"
             totalRowCount="#{ProductsList.productCount}"
             rowDataByKey="#{ProductsList.productByKey}"
             pageSize="20">
  <q:column id="ProductName"
            sortingExpression="#{product.name}"
            filterValues="#{ProductsList.col1FilterValues}"
            filterKind="dropDownField">
    <f:facet name="header">
      <h:outputText value="name"/>
    </f:facet>
    <h:outputText value="#{product.name}" />
  </q:column>
</q:dataTable>

Fetching Data on DataTable Rendering

When the DataTable component is rendered the data is fetched two times from the data source, the same as for the standard <h:dataTable> component. However, on the post requests, the data is fetched only once for the display-only DataTables. The display-only mode means that there is no UIInput, UICommand 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.

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 <q:singleRowSelection>, and for the multiple selection, use the same keyboardSupport attribute for <q:multipleRowSelection>. Keyboard-enabled pagination between records of the DataTable component is controlled by the paginationKeyboardSupport attribute of the <q: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 <q: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 <q:row> and <q:cell> tags.

The <q:row> and <q: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 <q:cell> tag (this feature is also known as a colspan feature).

To customize the individual rows, you should add the <q:row> tag as a child of the <q: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 <q: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 <q:row> tag will be applied to all data rows.

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

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

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


The individual cells can be customized by adding the <q:cell> tags as children of the <q:row> tag. There are two ways of specifying <q: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 free cells (<q: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 <q:cell> tags.

Regardless of the way that <q:cell> tags are applied to columns within a row, each <q: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 <q: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 <q:cell> tag. These components just like ordinary components inside of <q: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.

<q:dataTable var="product"
             value="#{ProductsList.products}">
  <q:row condition="#{product.number == 0}">
    <q:cell style="background-color: red;"/>
    <q:cell>
      <h:outputText value="Not available" style="color: red;"/>
    </q:cell>
  </q:row>
  ...
  <q:column>...</q:column>
  <q:column>...</q:column>
  ...
</q: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 <q:cell> tags to specify explicitly-bound cells. Note that unlike using free cells, using these attributes you can optionally make a single <q: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 <q: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:

<q:dataTable var="product"
             value="#{ProductsList.products}">
  <q:row condition="#{product.number == 0}">
    <q:cell columnIds="productName,productNubmer" style="color: red;"/>
  </q:row>
  ...
  <q:column id="productName">...</q:column>
  ...
  <q:column id="productNumber">...</q:column>
  ...
</q: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 curent cell. Returning true means that the <q: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:

<q:dataTable var="product"
             columnIndexVar="columnIndex"
             value="#{ProductsList.products}">
  <q:row>
    <q:cell condition="#{columnIndex % 2 == 0}" style="background: silver;"/>
  </q:row>
  ...
</q:dataTable>

Note
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 <q:row> tag. Just place free cells first, and explicitly-bound ones afterwards. If several <q: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 <q: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 QuipuKit 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 <q: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 that should be merged with this cell.

Note that the span attribute is just an additional possibility of the <q: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:

<q:dataTable var="product"
             value="#{ProductsList.products}">
  <q:row condition="#{rowIndex == 1}">
    <q:cell span="3">
      <h:outputText value="Merged cell contents"/>
    </q:cell>
  </q:row>
  ...
  <q:column>...</q:column>
  <q:column>...</q:column>
  <q:column>...</q:column>
  ...
</q: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, <q:dataTable> supports the align, bgcolor, dir, rules, width, border, cellspacing, and cellpadding attributes. Also, the <q:column>, <q:selectionColumn> and <q: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
Row that contains filter components filterRowStyle filterRowClass
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

Styles Example

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

<q: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"
             filterRowStyle="background-color:#faefd2">
  ...
</q:dataTable>

And here is the result:

Column Styles

You can apply styles to any type of a DataTable column: <q:column>, <q:selectionColumn>, and <q: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 <q: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 <q:columns> tag.

In addition, all of the above attributes, except filterCellStyle and filterCellClass can be specified for the <q: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 a filtering row. filterRowSeparator
A line that separates the footer section from the body section. footerHorizSeparator
Vertical lines between column headers. headerVertSeparator
Vertical lines between column footers. footerVertSeparator


Note
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:

<q: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"
             filterRowSeparator="1px dotted black"
             footerHorizSeparator="2px solid gray"
             headerVertSeparator="1px solid gray"
             footerVertSeparator="1px solid gray">
  ...
</q:dataTable>

And here is the result:

Note
If the DataTable component displays any gridlines or separators, the border, rules, and cellSpacing attributes of the <q: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 <q:row> and <q:cell> tags, respectively. For more details about these tags see section Customizing Individual Rows and Cells

You can also use the <q:rowStyle> and <q:cellStyle> tags to customize styles for individual rows and cells. Both these tags have the condition, style, and styleClass attributes. The condition attribute defines a condition under which the style specified in the style and styleClass attribute is applied to appropriate cells or rows. The condition attribute must be a value-binding expression.

In the following example, the cell background color in the second column is green if the price presented in it is lower than 100.

<q:dataTable var="product"
             value="#{ProductsList.products}"
             columnIndexVar="colIndex">
  <q:cellStyle condition="#{product.price < 100 && colIndex==1}"
               style="background-color: green"/>
  ...
</q:dataTable>

There are four request-scope variables enabling you to specify conditions for the <q:rowStyle> and <q:cellStyle> tags: var, rowIndexVar, columnIndexVar, columnIdVar. (See the section Request-Scope Variables for more information)

Note
Since QuipuKit version 1.4 the <q:rowStyle> and <q:cellStyle> tags are declared as deprecated. Use <q:row> and <q:cell> tags instead.

If you already use the <q:rowStyle> and <q:cellStyle> tags, the following steps should be made to migrate their usage to <q:row> and <q:cell> tags:

  1. Rename <q:rowStyle> and <q:cellStyle> tags to <q:row> and <q:cell>, respectively.
  2. Enclose all the <q:cell> tags into <q:row> tags with no additional attributes.

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 <q: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 <q: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 (<q:column>, <q:selectionColumn>, or <q:checkboxColumn> tags), or to a group of columns (<q: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 <q: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 <q:columns> tag.

The <q:singleRowSelection> and <q: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 <q:row> and <q: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).

You can also specify client-side event handlers for rows using the following attributes of the <q:dataTable> tag: rowOnclick, rowOndblclick, rowOnmousedown, rowOnmouseover, rowOnmousemove, rowOnmouseout, rowOnmouseup. When specifying these attributes, you can use request-scope variables defining parameters of the current row. These are the same parameters as those that can be used when defining column child components (see the section Request-Scope Variables).

Note
Please note that DataTable's attributes that used to specify row-specific events are declared as deprecated since there is a possibility to specify row-specific client-side events using the <q:row> tag.

Client-Side API

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

Methods of DataTable component Public method Description
selectAllRows() q_selectAllRows(tableId) Selects all rows in a table with the id specified in the tableId parameter. This method works with multiple selection mode.
clearSelection() q_clearSelection(tableId) Clears selection in a table with the id specified in the tableId parameter. This method works with any selection mode.
isSelectionEmpty() q_isTableSelectionEmpty(tableId) Returns "true" if the table has any selected rows. This method works with any selection mode.
getSelectedRowIndex() q_getSelectedRowIndex(tableId) 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) q_setSelectedRowIndex(tableId, rowIndex) Selects a row with the index specified in the rowIndex parameter. The table must be in single selection mode.
getSelectedRowIndexes() q_getSelectedRowIndexes(tableId) Returns an array of zero-based indexes of the current selected rows. The table must be in multiple selection mode.
setSelectedRowIndexes() q_setSelectedRowIndexes(tableId, rowIndexes) Selects rows with indexes that are passed in the rowIndexes array. The table must be in multiple selection mode.
getRowCount() q_getRowCount(tableId) Returns the number of rows currently visible in the table.
N/A q_refreshTable(tableId, submittedComponentIds, serverAction) Reloads the DataTable using Ajax without reloading the whole page.
Parameters:
  • tableId - client ID of a DataTable which should be refreshed.
  • submittedComponentIds - (optional, can be null) An array of client IDs for components those should be submitted in addition to the DataTable and its inner components.
  • serverAction - (optional, can be null) An action, which should be executed during this Ajax request. The method to which this action refers should be a public method without parameters and having a "void" return type. It should be specified in the form of "backingBeanName.methodName".

Known Issues

  • The DataTable component cannot be used inside DataTable, TreeTable or any other JSF components that replicate their child components during rendering.
  • QuipuKit components and the components that extend UIInput and UICommand cannot be used in the <q:cell> tag if this cell is rendered for the several columns.
  • RichFaces SuggestionBox cannot be used inside rows of the QuipuKit DataTable component. Note the you can still use the SuggestionBox component in DataTable's "header", "footer", "above", "below" facets.
QuipuKit