TreeTable


The TreeTable component displays hierarchical data in a tabular format. One of its columns displays a tree structure in which each row representing a node can be expanded to reveal lower-level rows of data. In general, the TreeTable component provides most of the functionality of the QuipuKit DataTable component.

Note

It is a good idea to read DataTable documentation before proceeding with the TreeTable component.

Key Features

Specifying the Content

To add the TreeTable component to a page, use the <q:treeTable> tag. To specify the content of the TreeTable, you should configure the tree structure and columns. The tree structure is specified as a hierarchy of objects storing node data. The TreeTable component displays a row for each tree node. Specifying the columns defines how the cell contents are derived from the node data that corresponds to the row which holds this cell.

The tree structure in the TreeTable component can be specified either right in the page or in a backing bean. See the sections Static Tree Structure and Dynamic Tree Structure below for more details.


Columns in the TreeTable component are configured in the way similar to the DataTable configuration, i.e. by nesting appropriate column tags within the <q:treeTable> tag. The TreeTable component supports several column types: <q:column>, <q:treeColumn> and <q:selectionColumn> (for more information, see the section Specifying Columns below). Child components of the column tag define the contents of the column cells based on the corresponding row's node data. When the TreeTable component is being rendered, it repeatedly makes current the node 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 the next section).

Row Request-Scope Variables

When specifying child components to be displayed in the TreeTable columns, you can use request-scope variables that reference the current row's node parameters. There are four such variables. To use any of them, you should declare its name in the corresponding attribute of the <q:treeTable> tag:

  • var (required) - The name of a request-scope variable under which the current node data is available.
  • nodePathVar (optional) - The name of a request-scope variable under which the full path of the current node is available. This variable has the teamdev.jsf.component.treetable.TreePath type. Instances of the TreePath class are used to reference a node in the tree structure by its node value and node values of all its parent nodes.
  • nodeLevelVar (optional) - The name of an integer request-scope variable under which the level number of the current node is available, where "0" corresponds to the top-most level.
  • nodeHasChildrenVar (optional) - The name of a boolean request-scope variable under which the flag indicating whether a node has children is available.

After their declaration, the variables will be available under the declared names when specifying attribute values in JSP source with EL code. If the value is evaluated by a backing bean method, you can use the teamdev.jsf.component.util.FacesUtil.getRequestMapValue method to retrieve a request-scope variable by its name.
Note that the request-scope variables are available only for a limited set of the TreeTable attributes.

<q:treeTable var="nodeObject" nodeLevelVar="nodeLevel">
...
</q:treeTable>

Model Node Objects Requirements

There are two ways of defining the tree structure of the TreeTable component. Either way, the node data objects provided by the tree structure must meet the following requirements:

  • They should be serializable.
  • They should correctly implement the equals and hashCode methods.

If node data objects do not meet these requirements, then each node should provide a "node key" object that must uniquely identify the appropriate node and satisfy the above mentioned requirements. The way node keys are specified depends on the type of the tree structure used. For more information about the tree structure, see the sections Static Tree Structure and Dynamic Tree Structure below.

Static Tree Structure

In a static tree structure, the hierarchy of nodes is defined right on the page within the <q:treeTable> tag. To specify the static structure, you should place the <q:staticTreeStructure> tag into the <q:treeTable> tag. This tag should contain a hierarchy of the <q:treeNode> tags for each node.

The <q:treeNode> tag has two attributes: value (required) and nodeKey (optional). The value attribute specifies the node data object and can be either a value-binding expression that references any object or just a String (as in the example below). If present, the nodeKey attribute specifies the node key object for this node, as described in the section above.

The following example shows the TreeTable component with an explicitly defined hierarchy of nodes.

<q:treeTable var="color">
  <q:staticTreeStructure>
    <q:treeNode value="Colors">
      <q:treeNode value="Warm colors">
         <q:treeNode value="Red"/>
         <q:treeNode value="Yellow"/>
      </q:treeNode>
      <q:treeNode value="Cold colors">
        <q:treeNode value="Blue"/>
        <q:treeNode value="Purple"/>
      </q:treeNode>
    </q:treeNode>
  </q:staticTreeStructure>
  <q:treeColumn>
    <h:outputText value="#{color}">
    </h:outputText>
  </q:treeColumn>
</q:treeTable>

Dynamic Tree Structure

In case of a dynamic tree structure, the nodes are not specified explicitly; instead, you specify the rules of how to retrieve the nodes. This gives you the ability to provide flexible hierarchies of objects from any data source.

To specify a dynamic tree structure, use the <q:dynamicTreeStructure> tag. The hierarchy in the dynamic tree structure is defined by specifying an expression for retrieving child nodes of a given node. This expression is specified using the nodeChildren attribute. Whenever the TreeTable component needs to retrieve a list of children for a specific node, it makes this node current and evaluates the expression specified by the nodeChildren attribute. The parameters of the current node are available in the expression through request-scope variables.

Building of the tree structure starts from retrieving the list of top-level nodes. As with any other nodes, the top-level nodes are calculated with the nodeChildren attribute, but in this case there is no parent node. After retrieving the top-level nodes, the TreeTable component retrieves child nodes for each of them recursively using the same attribute.

The <q:dynamicTreeStructure> tag provides the following attributes:

  • nodeChildren - This is a required attribute that should be defined as a value-binding expression. This expression should provide a list of child node data objects for the parent node. The parent node whose children should be retrieved can be identified through the request-scope variables whose names are specified with the var, nodePathVar, or nodeLevelVar attributes of the <q:treeTable> tag (for more information about these attributes, see the section Row Request-Scope Variables above). For retrieving top-level nodes, these variables has the following values: var has a value of null, nodePathVar has a value of null, and nodeLevelVar has a value of -1.
  • nodeHasChildren - This is an optional boolean attribute that specifies whether the node has children or not. When the attribute is set, the TreeTable component doesn't calculate the nodeChildren attribute when it's necessary to know whether a node has any children. This defers retrieval of child nodes until they are actually needed and can greatly reduce the time of the tree model retrieval if calculation of the nodeChildren attribute's expression is time-consuming. The nodeHasChildren attribute must be set as a value-binding expression. The node that should be checked for the presence of children can be identified using the same request-scope variables as in the nodeChildren attribute.
  • nodeKey - This attribute defines the key node object if it is required (see the section Model Node Objects Requirements for more details). The node for which the node key should be returned can be identified using the same request-scope variables as in the nodeChildren attribute.

This example shows the TreeTable component that references the Messages backing bean.

<q:treeTable var="message">
  <q:dynamicTreeStructure nodeChildren="#{Messages.nodeChildren}"
                          nodeHasChildren="#{Messages.nodeHasChildren}"
                          nodeKey="#{message.id}"/>
  <q:treeColumn>
    <f:facet name="header">
      <h:outputText value="Subject"/>
    </f:facet>
    <h:outputText value="#{message.subject}"/>
  </q:treeColumn>
  <q:column>
    <f:facet name="header">
      <h:outputText value="Author"/>
    </f:facet>
    <h:outputText value="#{message.author}"/>
  </q:column>
</q:treeTable>

In the following example, you can see a method from the backing bean of the previous example:

public List getNodeChildren() {
    ForumMessage message =
            (ForumMessage) FacesUtil.getRequestMapValue("message");
    if (message == null)
      return myRootMessages;
    else
      return message.getReplies();
  }

  public boolean isNodeHasChildren() {
    ForumMessage message =
            (ForumMessage) FacesUtil.getRequestMapValue("message");
    return message.hasReplies();
  }

Specifying Columns

Specifying columns defines the contents of all the cells of the TreeTable component. 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 Row Request-Scope Variables).

The TreeTable component supports three types of columns:

  • <q:column> - This is a basic column that renders the specified cell contents.
  • <q:treeColumn> - This column shows the hierarchy position of each node by indenting it and also provides controls for expanding/collapsing child nodes (called "expansion toggle button").
  • <q:selectionColumn> - This column shows check boxes that reflect a row selection state.

Please note that unlike the DataTable, the TreeTable component doesn't support <q:checkboxColumn>.

The list of columns is specified using the <q:column> tag for each column. The use of the <q:column> tag is the same as for the DataTable component. The content of the <q:column> tag is used for rendering the cells belonging to that column. The column also has the "header" and "footer" facets that can be used to specify its header and footer respectively.

When specifying child components to be displayed in the column, in addition to the variable specified in the var attribute, you can use variables whose names are specified in the nodeLevelVar, nodePathVar or nodeHasChildren attributes of the TreeTable component (see the section Row Request-Scope Variables for more details). Note that these variables are not mandatory and you can use them as needed.

To specify a column for displaying the tree structure, use the <q:treeColumn> tag. The use of the <q:treeColumn> tag is similar to the <q:column> tag with the exception of some features described below.

The following example shows a two-column TreeTable component with headers for each column.

<q:treeTable var="message">
  <q:dynamicTreeStructure nodeChildren="#{Messages.nodeChildren}" />
  <q:treeColumn>
    <f:facet name="header">
      <h:outputText value="Subject"/>
    </f:facet>
    <h:outputText value="#{message.subject}"/>
  </q:treeColumn>
  <q:column>
    <f:facet name="header">
      <h:outputText value="From"/>
    </f:facet>
      <h:outputText value="#{message.author.userName}"/>
  </q:column>
</q:treeTable>

The <q:treeColumn> tag provides several additional attributes for customizing its appearance and nodes. The levelIndent attribute lets you specify the horizontal offset between the node levels. It can be specified in pixels (px), millimeters (mm), em dashes (em), etc. For example, "30px". The showAsTree boolean attribute ("true" by default) allows you to dynamically change the column appearance. So when the attribute is set to "false", the column looks like an ordinary column specified with the <q:column> tag. The expansionToggleCellStyle and expansionToggleCellClass attributes are used to define a style for a cell that contains expansion toggle (+ and -) buttons.


The following example shows the TreeTable component in which the nodes are indented by 30 pixels and a style is applied to the cell with an expansion toggle button:

<q:treeTable var="message"
    expansionToggleCellStyle="vertical-align: top; padding-top: 4px"
    levelIndent="30px">
  <q:treeColumn>
    <f:facet name="header">
      <h:outputText value="Subject"/>
    </f:facet>
      <h:outputText value="#{message.subject}"/>
  </q:treeColumn>
</q:treeTable>

Changing Column Order

The columnsOrder attribute of the <q:treeTable> tag lets you explicitly specify the order in which the columns will be displayed. This attribute 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 appear. If the columnsOrder attribute is not specified, all columns are rendered in the order they are defined. Otherwise, only the columns whose IDs are included into this list are rendered.

In the example below, the columns in the TreeTable component are ordered explicitly.

<q:treeTable var="message"
              columnsOrder="#{Messages.columnsOrder}">
  <q:dynamicTreeStructure nodeChildren="#{Messages.nodeChildren}" />
  <q:treeColumn id = "subjectColumn"> ... </q:treeColumn>
  <q:column id = "authorColumn"> ... </q:column>
  <q:column id = "sentColumn"> ... </q:column>
  <q:column id = "sizeColumn"> ... </q:column>
</q:treeTable>

Concurrent Data Modifications

The TreeTable component allows you to embed 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 nodes, the other can delete one of these nodes. The TreeTable component provides a mechanism for resolving this kind of problems. If node data meets the node objects requirements, edited data is saved properly, even if the node order has changed.

Headers and Footers

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

The TreeTable component also has two special areas that are located right before and after the table. The contents of these areas can be specified with the "above" and "below" facets of the <q:treeTable> tag.

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

<q:treeTable var="message" style="border:dotted 1px gray">
...
      <f:facet name="above">
        <h:outputText value="'Above' facet goes before the TreeTable"/>
      </f:facet>
      <f:facet name="header">
        <h:outputText value="'Header' facet goes as the first row of the TreeTable"/>
      </f:facet>
      <f:facet name="footer">
        <h:outputText value="'Footer' facet goes as the last row of the TreeTable"/>
      </f:facet>
      <f:facet name="below">
        <h:outputText value="'Below' facet goes after the TreeTable"/>
      </f:facet></q:treeTable>

The following figure shows all the facets defined in the previous example:

Empty Data Message

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

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 using the noFilterDataMessage facet.

The example below shows a customized message for empty data in the TreeTable component.

<q:treeTable var="message"
       noDataRowStyle="color:red; font-weight:bold; font-syze:20pt">
  <f:facet name="noDataMessage">
       <h:outputText value="There is no data to display">
  </f:facet>
...
</q:treeTable>

Sorting

The TreeTable component supports column-wise sorting. The user should click the header of any sortable column to sort the data displayed in it. Subsequent clicks on the header changes the sort order from ascending to descending, and vice versa.

Data can be sorted only by "sorting-aware" columns. To make a specific column sortable, you should specify the sortingExpression and, optionally, sortingComparator attributes for that column. The sortingExpression attribute specifies the value that should be used when sorting the rows by that column. 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 specified, 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.

When the TreeTable component is loaded for the first time, its data is rendered unsorted. You can specify which column will be sorted on page load and in what order using the sortColumnId and sortAscending attributes. The sortColumnId attribute is a string attribute, where you specify the ID of the 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 following example shows the TreeTable component in which messages appear sorted by subject on page load:

<q:treeTable var="message" sortLevel="0">
  <q:dynamicTreeStructure nodeChildren="#{Messages.nodeChildren}" />
  <q:treeColumn id="subjectColumn"
                sortingExpression="#{message.subject}">
    <f:facet name="header">
      <h:outputText value="Subject"/>
    </f:facet>
    <h:outputText value="#{message.subject}"/>
  </q:treeColumn>
  <q:column id="authorColumn">
    <f:facet name="header">
      <h:outputText value="From"/>
    </f:facet>
    <h:outputText value="#{message.author.userName}"/>
  </q:column>
</q:treeTable>

Because the TreeTable component displays hierarchical data, sorting can be performed only across a certain level of the hierarchy, i.e. by comparing the nodes only with their siblings. So sorting in the TreeTable component is performed among children of each separate node, without mixing with nodes of different parents.

The level at which to perform sorting is specified by the sortLevel integer attribute of the <q:treeTable> tag. The default value is -1, which means that sorting is applied to all levels of the hierarchy in the TreeTable component. When set to "0" (top-most level) or greater, sorting is restricted to only one specified level. For example, a value "0" means that only the nodes at the top-most level are sorted against each other, while all their children remain unsorted. A value "1" means that only the nodes of the level next to the top-most one are sorted, while all other levels are not affected.

Sorting-Related Styles

You can apply styles to any part of a sorted column. The available attributes are summarized in the table below:

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

Filtering

The TreeTable component allows the user to perform filtering over the original tree structure. Each column 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, the hierarchy of nodes in the TreeTable component gets filtered by the specified value, so that only the nodes satisfying the filter criterion are displayed. If a filter value is specified for more than one column, only the nodes that satisfy all of the criteria are displayed.

To provide filtering for a column, you should first specify the filterExpression attribute for a corresponding <q:column> tag. This attribute specifies the row value that will be matched against a filter criterion entered by the user. The attribute must be a value-binding expression that specifies the value by which the data will be filtered.

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

When specifying the filterExpression attribute, you can use the var, nodePath, nodeLevel, nodeHasChildren request-scope variables (for more information about them, read the section Row Request-Scope Variables).

The TreeTable component provides several types of filter components for filtering its data. To specify the type of a filter component, set the filterKind attribute of the <q:treeTable> tag 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 component, shows all the unique values and, in addition, allows text entry. Records are filtered by a substring in a case-insensitive manner.

In addition to the unique column values, the "comboBox" and "dropDownField" filter components provide three predefined filter values:

  • <All> - Displays all records, i.e. no data is filtered.
  • <Empty> - Displays only the records with empty values.
  • <Non-empty> - Displays all records with non-empty values.

You can change the text of the predefined filter values for the "comboBox or "dropDownField" filter components by using the allRecordsFilterName, emptyRecordsFilterName, and nonEmptyRecordsFilterName attributes of <q:treeTable> tag.

To explicitly specify the filter values that will appear in the "comboBox" or "dropDownField" components instead of all possible values by setting the filterValues attribute of the <q:column> tag.

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

In the following example, a "searchField" filter component is used for filtering messages by subject:

<q:treeTable var="message">
  <q:dynamicTreeStructure nodeChildren="#{Messages.nodeChildren}" />
  <q:treeColumn id="subjectColumn"
                filterExpression="#{message.subject}"
                filterKind="searchField">
    <f:facet name="header">
      <h:outputText value="Subject"/>
    </f:facet>
    <h:outputText value="#{message.subject}"/>
  </q:treeColumn>
</q:treeTable>

You can use the filterValues attribute of the <q:column> or <q:treeColumn> 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> or <q:treeColumn> tag. This attribute should be bound to an instance of the teamdev.jsf.component.datatable.TextFilterCriterion class for the "searchField" and "dropDownField" filter components. For the "comboBox" filter component, the filterValue attribute should be bound to an instance of the teamdev.jsf.component.datatable.TextFilterCriterion, teamdev.jsf.component.datatable.EmptyRecordsCriterion or teamdev.jsf.component.datatable.NonEmptyRecordsCriterion classes.

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

<q:treeTable var="message">
  <q:dynamicTreeStructure nodeChildren="#{Messages.nodeChildren}" />
  <q:treeColumn id="subjectColumn"
                filterExpression="#{message.subject}"
                filterKind="searchField">
    <f:facet name="header">
      <h:outputText value="Subject"/>
    </f:facet>
    <h:outputText value="#{message.subject}"/>
  </q:treeColumn>
  <q:column filterExpression="#{message.author}"
            filterKind="dropDownField"
            filterValues="#{Messages.authors}"
            filterValue="#{Messages.selectedAuthor}">
    <f:facet name="header">
      <h:outputText value="author"/>
    </f:facet>
    <h:outputText value="#{message.author}" />
  </q:column>
</q:treeTable>

Filtering-Related Styles

You can apply a style to the row that contains a filter component by using the filterRowStyle and filterRowClass attributes. The filterRowSeparator attribute lets you can create a style for a line that separates the row with an embedded filter component and the column header.

Note
You should specify the filterRowSeparator attribute in the same way as the CSS border property but without the prefix "border:". For example, filterRowSeparator="1px dotted black" .

Because the TreeTable component displays hierarchical data, the way it shows filtered nodes is different from how filtered rows are displayed in the DataTable. While the DataTable component displays only the rows that match filter criteria, the TreeTable component may display rows for the nodes that are not accepted by filter criteria. This happens when the TreeTable component needs to display a node at some deep level of the hierarchy which is accepted by filter criteria, whereas its parent nodes are not. In this case, all parent nodes of the accepted nodes are also displayed for the sake of keeping visible that part of the hierarchy that leads to the accepted node. By default, these "auxiliary" nodes are grayed out to distinguish them from filtered nodes.

You can customize the appearance of nodes that satisfy filter criteria by using the filterAcceptedRowStyle and filterAcceptedRowClass attributes. To define a style for the nodes that don't meet filter criteria but are needed to keep the hierarchy visible, use the filterSubsidiaryRowStyle and filterSubsidiaryRowClass attributes.

Node Selection

The selection feature lets the user select one or more nodes in the TreeTable component. Selection in the TreeTable is similar in usage to that in the DataTable component. The difference, however, is how single and multiple selection modes are configured in the TreeTable component (see the sections below). To learn more about the selection feature, please refer to the appropriate section in the DataTable documentation.

Single Selection Mode

To provide single node selection for the TreeTable component, use a child <q:singleNodeSelection> tag. To detect which node is currently selected or to change selection, the <q:singleNodeSelection> tag provides two value-binding attributes that can be bound to a backing bean:

  • nodeData - Defines the node data object for a currently selected node. A value of null means no node is currently selected.
  • nodePath - Defines the full path of a currently selected node. A value of null means no node is currently selected. This attribute should be bound to a property of the teamdev.jsf.component.treetable.TreePath type. Instances of the TreePath class are used to reference a node in the tree structure by its node value and node values of all its parent nodes.

If both attributes are specified, but refer to different nodes, the nodePath attribute takes precedence.

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

To disable selection in the TreeTable component, set the enabled attribute of the <q:singleNodeSelection> tag to "false" (by default, it is "true").

The following example shows configuration of single node selection with disabled keyboard support.

<q:treeTable var="message">
  <q:singleNodeSelection
          nodeData="#{Messages.selectedNodeData}"
          keyboardSupport="false"/>
  <q:dynamicTreeStructure
          nodeChildren="#{Messages.nodeChildren}" />
  <q:treeColumn>
    <f:facet name="header">
      <h:outputText value="Subject"/>
    </f:facet>
    <h:outputText value="#{message.subject}"/>
  </q:treeColumn>
</q:treeTable>

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

  • Using the onchange attribute of the <q:singleNodeSelection> tag. This is a client-side event attribute in which you should specify JavaScript code that should be executed every time the user changes selection.
  • Using the action attribute of the <q:singleNodeSelection> tag. The use of this attribute is similar to the action attribute of the HTMLCommandButton component. This 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, the action attribute causes the form submission on selection change.

You can apply a style to a selected row by using the style and styleClass attributes of the <q:singleNodeSelection> tag.

Multiple Selection Mode

To provide multiple selection for the TreeTable component, use a child <q:multipleNodeSelection> tag. The only difference between specifying single and multiple node selection is that the <q:multipleNodeSelection> tag has the nodeDatas and nodePaths attributes instead of the nodeData and nodePath attributes. These attributes must be specified as value-binding expressions that reference a list, set or array of node data objects and teamdev.jsf.component.treetable.TreePath instances, respectively. Empty lists mean an empty selection.

All other features, including selection change notifications and styles, are configured in the same way as for single node selection.

The following example shows the TreeTable component in multiple node selection mode.

<q:treeTable var="message">
  <q:multipleNodeSelection
          nodeDatas="#{Messages.selectedNodeDatas}" />
  <q:dynamicTreeStructure
          nodeChildren="#{Messages.nodeChildren}" />
  <q:treeColumn>
    <f:facet name="header">
      <h:outputText value="Subject"/>
    </f:facet>
    <h:outputText value="#{message.subject}"/>
  </q:treeColumn>
</q:treeTable>

Dynamic Data Loading

The TreeTable component supports dynamic data loading for such features as sorting, filtering, and node expansion, using Ajax technology. The useAjax boolean attribute specifies whether or not to use Ajax. By default, it is "true", which means Ajax is enabled.

If Ajax is not used, when the TreeTable component requires data update, the entire page is submitted and re-rendered completely with new data for the TreeTable. With Ajax, the page is submitted "behind the scenes" with only the TreeTable component being re-rendered. In case of node expansion, when Ajax is enabled only newly expanded nodes are loaded from the server.

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

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

You can also specify an action that is executed during the Ajax request using the serverAction parameter of the q_refreshTreeTable 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_refreshTreeTable function usage :

<h:form id="form1">
  <h:commandButton type="button"
                   id="addRequestBtn"
                   value="Add"
                   alt="Adds a new sibling request"
                   onclick="q_refreshTreeTable('form1:requestsTreeTable', null, 'RequestsTreeTableBean.addRequest');"/>
  <q:treeTable id="requestsTreeTable"...>
  ...
  </q:treeTable>
</h:form>

See also the Client-Side API section.

Note
The q_refreshTreeTable function reloads the TreeTable component asynchronously, i.e. it initiates an Ajax request for reloading the TreeTable 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 TreeTable component: sorting, filtering, expanding nodes, refreshing TreeTable 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 an 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:treeTable ...>
...
<f:facet name="below">
<h:panelGroup id="panelGroup">
  <h:outputText value="#{BackingBean.value1}"/>
  <h:outputText value="#{BackingBean.value2}"/>
</h:panelGroup>
</f:facet>
</q:treeTable>

Expanding and Preloading Nodes

Using of the foldingEnabled attribute of the <q:treeTable> tag allows you to specify whether the user can expand/collapse nodes in the TreeTable component. By default, it is "true".

By default, when the TreeTable component is loaded, all the nodes are collapsed. You can change this behavior by setting the expansionState attribute to one of the following values:

  • "allExpanded" - All nodes are displayed in the expanded state.
  • "allCollapsed" - All nodes are displayed in the collapsed state.
  • "levelsExpanded:NUMBER", where NUMBER is an integer number greater than or equal to zero. It specifies the hierarchy level at which the nodes are displayed in the expanded state, while all nodes below this level are collapsed. For example, expansionState="levelsExpanded:1" means that only the root nodes are expanded. A value of "0" means that no nodes are expanded.

If it's necessary to store the node state after the user leaves a page containing the TreeTable component, you should bind the expansionState attribute to the property of teamdev.jsf.component.treetable.ExpansionState type that resides in a session-scope backing bean.

Although the TreeTable component can be configured to load with all nodes collapsed, you can specify that some of the collapsed nodes are preloaded to the client using the preloadedNodes attribute. This makes nodes expand faster. That is, when a collapsed node whose child nodes are preloaded is expanded by the user, these nodes will be shown immediately without any server request being sent. The preloadedNodes attribute can take one of the following values:

  • "none" - No children of collapsed nodes will be preloaded. This is a default value.
  • "all" - All children of collapsed nodes at all levels will be preloaded. So the entire TreeTable component can be browsed without any requests to the server.
  • "levelsPreloaded:NUMBER", where NUMBER is a positive integer number. It indicates the total number of node levels, starting from the top-most one, in which the nodes will be preloaded. For example, preloadedNodes="levelsPreloaded:2" means that only root nodes and their immediate children are preloaded. So if, for example, the TreeTable is loaded with all nodes collapsed, the root nodes can be expanded without requests to the server, and deeper levels will require a request to the server to load missing nodes.

There are two ways of sending a request to the server to load missing nodes. This depends on the value of the useAjax attribute (see the section Dynamic Data Loading ). By default, it is "true", which means that only nodes that need to be loaded are requested from the server. Otherwise, the entire page is reloaded along with the expanded nodes.

Keyboard Navigation

The TreeTable component provides keyboard support for selecting and expanding/collapsing nodes. When single or multiple selection is enabled, a selected node can be changed with the keyboard. This feature is enabled by default, and, if necessary, you can disable it by setting the keyboardSupport boolean attribute of the <q:singleNodeSelection> or <q:multipleNodeSelection> tags to "false".

If selection is provided, and therefore, there's nothing to control from the keyboard, the TreeTable component is not focusable. However, if selection is configured in the TreeTable component and keyboard support is enabled, the TreeTable automatically becomes focusable. So you can either press the Tab key or click anywhere inside the TreeTable component to focus it.

You can customize the appearance for a focused TreeTable component by using the focusedStyle and focusedClass attributes.

The following keyboard shortcuts are available for node selection and expansion:

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.
Shift+Up Arrow, Down Arrow, End, Home Shift+Up Arrow, Down Arrow, , Select adjacent rows. Note that only contiguous row ranges can be selected with the keyboard.
Left Arrow/Minus Sign Left Arrow Collapse a currently selected node.
Right Arrow/Plus Sign Right Arrow Expand a currently selected node.

In addition the user can select not contiguous row ranges by pressing Ctrl key and clicking rows with mouse.

Customizing Styles

Section Styles

By default, the TreeTable component uses a default style. To turn the it off, set the applyDefaultStyle boolean attribute of the <q:treeTable> tag to "false".
Like the <q:dataTable> tag and HTML <table> tag, the <q:treeTable> tag supports the align, bgcolor, dir, rules, width, border, cellspacing, and cellpadding attributes.

The TreeTable component provides a number of style attributes for customizing its header, body, and footer sections.

Part of TreeTable Style attributes Class attributes Example legend
Entire component style styleClass  
Entire component in the rollover state rolloverStyle rolloverClass  
TreeTable header headerSectionStyle headerSectionClass
TreeTable body bodySectionStyle bodySectionClass
TreeTable footer footerSectionStyle footerSectionClass

Note that the text-related part of the style and styleClass attributes (font, color, text-alignment, etc.) will not be applied correctly to all parts of the TreeTable component. To specify text styles, use the textStyle and textClass attributes instead of style and styleClass.

Row Styles

The TreeTable component allows you to define styles for the rows that span the header and footer of the component or its individual columns. All row style-related attributes of the <q:treeTable> tag 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 footerRowClass
Table footer row commonFooterRowStyle commonFooterRowClass

Styles Example

The following example shows the styles applied to the sections of TreeTable component and rows that span the column headers and footers:

<q:treeTable id="treeTable" var="message"
             expansionState="#{TreeTableBean.forumTreeTableExpansionState}"
             nodeLevelVar="level" width="40%"
             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:treeTable>

And here is the result:

Column Styles

A style can also be defined for a specific column of the TreeTable component. The style attributes listed below can be applied to all supported column tags:

Part of the column Style attributes Class attributes
Entire column style styleClass
Column header headerStyle headerClass
Column body bodyStyle bodyClass
Column footer footerStyle footerClass

The appearance of rows in the body section of the TreeTable component can be customized with the bodyRowStyle and bodyRowClass attributes of the <q:treeTable> tag. Additionally, you can use the bodyOddRowStyle and bodyOddRowClass attributes to define a style for odd rows. Creating alternate styles brings contrast between adjacent rows.

Other Styles

The TreeTable component support styles related to the sorting and filtering features. They are described in the sections Sorting and Filtering. Additional styles are provided for the cell containing an expansion toggle button (see the toggle styles) and for the message displayed for empty data (see the section Empty Data Message).

Gridline Styles

You can specify styles for any type of separator lines within the TreeTable component. Each of them has its own attribute which should be used within the <q:treeTable> tag.

Type of separators Attribute
Horizontal lines between body rows horizontalGridLines
Vertical lines between columns in the body area verticalGridLines
Table header bottom line commonHeaderSeparator
Table footer upper line commonFooterSeparator
Header bottom line headerHorizSeparator
Footer upper line footerHorizSeparator
Vertical lines between column headers headerVertSeparator
Vertical lines between column footers footerVertSeparator

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

Note that if the TreeTable component has any gridlines or separators specified, the border, rules, and cellSpacing attributes of the <q:treeTable> tag take no effect.

The following example shows customized gridlines and separators in the TreeTable component:

<q:treeTable var="message"
             horizontalGridLines="1px dotted gray"
             verticalGridLines="1px dotted gray"
             commonHeaderSeparator="3px solid gray"
             commonFooterSeparator="3px solid gray"
             headerHorizSeparator="2px solid gray"
             footerHorizSeparator="2px solid gray"
             headerVertSeparator="1px solid gray"
             footerVertSeparator="1px solid gray"
             filterRowSeparator="1px dotted black">
  <q:singleNodeSelection/>
  <q:dynamicTreeStructure nodeChildren="#{Message.nodeChildren}"/>
  <q:treeColumn>
    <f:facet name="header">
      <h:outputText value="Subject"/>
    </f:facet>
    <h:outputText value="#{message.subject}"/>
  </q:treeColumn>
</q:treeTable>

And here is the result:

Conditional Styles

While all the styles described in the previous sections are applied to the appropriate areas of the TreeTable 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.

To use conditional styles, nest the <q:rowStyle> or <q:cellStyle> tags within the TreeTable component. Both tags have the condition, style and styleClass attributes. The condition attribute determines the condition under which the style specified in the style and styleClass attributes is applied to cells or rows. The condition attribute must be a value-binding expression evaluating to a boolean.

In the following example, a conditional style is applied to all rows of the top-most level.

<q:rowStyle condition="#{level == 0}"
            style="font-weight: bold; background: silver"/>
<q:singleNodeSelection/>
<q:dynamicTreeStructure nodeChildren="#{Message.nodeChildren}"/>
<q:treeColumn>
  <f:facet name="header">
    <h:outputText value="Subject"/>
  </f:facet>
  <h:outputText value="#{message.subject}"/>
</q:treeColumn>

When specifying conditions for the <q:rowStyle> and <q:cellStyle> tags, you can use the following request-scope variables: nodeLevel, nodePath, nodeHasChildren (see the section Row Request-Scope Variables for more information).

There are two more variables provided to define a cell style condition. To use them, you should declare their names in the corresponding attribute of the <q:treeTable> tag:

  • columnIndexVar - Defines the name of a request-scope variable under which the column index will be available. It is a zero-based integer number.
  • columnIdVar - Defines the name of a request-scope variable under which the column ID will be available. It is a string variable that contains the ID specified in the corresponding column tag.

Style Hierarchy

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

Specifying User Events

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

In addition, you can specify client-side events for any type of a TreeTable column. 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

The <q:singleNodeSelection> and <q:multipleNodeSelection> tags provide the onchange event. You can specify it by using the onchange attribute.

You can also specify client-side event handlers for rows by using the following attributes of the <q:treeTable> tag: rowOnclick, rowOndblclick, rowOnmousedown, rowOnmouseover, rowOnmousemove, rowOnmouseout, rowOnmouseup.

When specifying all the above attributes, you can use request-scope variables that define parameters of the current node. These are the same parameters as those that can be used when defining column child components (see the description of the var, nodePathVar and nodeLevelVar attributes in the section Specifying the Content).

Client-Side API

The TreeTable component has the following public client-side API methods:

Method of TreeTable component Public method Description
isSelectionEmpty() q_isTreeTableSelectionEmpty(treeTableId) Returns "true" if the TreeTable component has any selected nodes. This method works with any selection mode.
getSelectedNodeCount() q_getSelectedNodeCount(treeTableId) Returns the number of selected nodes, or 0 if no nodes are selected. This method works with any selection mode (single or multiple).
N/A q_refreshTreeTable(treeTableId, submittedComponentIds, serverAction) Reloads the TreeTable using Ajax without reloading the whole page.
Parameters:
  • treeTableId - client ID of a TreeTable which should be refreshed.
  • submittedComponentIds - (optional, can be null) An array of client IDs for components those should be submitted in addition to the ??TreeTable 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".
QuipuKit