TreeTable |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Developer’s Guide Home
Installation and Configuration Components Index Calendar Chart Confirmation Data Table Date Chooser Drop Down Field Dynamic Image Folding Panel Graphic Text Hint Label Popup Layer Suggestion Field Tab Set Tabbed Pane Tree Table Two List Selection Focus Load Bundle Scroll Position Ajax Support Validation Framework Tag Reference |
Note Key Features
Specifying the ContentTo 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.
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). Request-Scope VariablesWhen specifying child components to be displayed in 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:
In addition there are two more variables provided to define a cell style condition. These variables are available when specifying the condition for the <q:cell> and <q:cellStyle> tags:
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 getRequestMapValue() method to retrieve a request-scope variable by its name. <q:treeTable var="nodeObject" nodeLevelVar="nodeLevel"> ... </q:treeTable> Model Node Objects RequirementsThere 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:
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 StructureIn a static tree structure, the hierarchy of nodes is defined right in 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 StructureIn 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 their 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:
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 ColumnsSpecifying 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 Request-Scope Variables). The TreeTable component supports three types of columns:
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 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. And you can customize expansion toggle images (+/-), using the expandedToggleImageUrl and collapsedToggleImageUrl attributes.
<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> Specifying Dynamic ColumnsIn addition to column types listed in section Specifying Columns the TreeTable provides an ability to specify dynamic number of columns. To add dynamic columns to the TreeTable, use the <q:columns> child tag of the <q:treeTable> 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 TreeTable 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:treeTable> 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 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 TreeTable. The following example demonstrates the usage of the <q:columns> tag: <q:treeTable var="node"> <q:dynamicTreeStructure nodeChildren="#{treeTableBean.nodeChildren}"/> <q:treeColumn> <f:facet name="header"> <h:outputText value="name"/> </f:facet> <h:outputText value="#{node.name}"/> </q:treeColumn> <q:columns value="#{treeTableBean.dynamicColumns}" var="col"> <f:facet name="header"> <h:outputText value="#{col}"/> </f:facet> <h:inputText value="#{node.dynamicColumns[col]}"/> </q:columns> </q:treeTable> As an ordinary <q:column> tag, the <q:columns> tag supports sorting, filtering, style customization and columns-specific events. Grouping ColumnsIt 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:
Here's a simple example of using column groups: <q:treeTable value="#{treeTableBean.folders}" var="folder"> <q:treeColumn> <f:facet name="header"> <h:outputText value="Name"/> </f:facet> <h:outputText value="#{folder.name}"/> </q:treeColumn> <q:column> <f:facet name="header"> <h:outputText value="Date created"/> </f:facet> <h:outputText value="#{folder.creationDate}"/> </q:column> <q:columnGroup> <f:facet name="header"> <h:outputText value="Attributes"/> </f:facet> <q:column> <f:facet name="header"> <h:outputText value="Read-only"/> </f:facet> <h:outputText value="#{product.attributes.readOnly}"/> </q:column> <q:column> <f:facet name="header"> <h:outputText value="Hidden"/> </f:facet> <h:outputText value="#{product.attributes.hidden}"/> </q:column> </q:columnGroup> </q:dataTable> Note that there are both the columns those are enclosed into <q:columnGroup> tag and the columns those are 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 OrderThe 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> Column ResizingIt is possible to let the user resize columns by adding the <q:columnResizing> tag as a child of <q:treeTable> tag. When column resizing is turned on, the user can drag the column header separators to resize columns. The total TreeTable width is not affected by the process of resizing columns. It should also be noted that if a TreeTable 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 TreeTable is loaded with its width properly calculated using the specified relative width, though after the page is loaded the TreeTable'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 TreeTable: <q:treeTable var="message" columnsOrder="#{Messages.columnsOrder}" width="100%"> <q:columnResizing resizeHandleWidth="10px" minColWidth="50px"/> <q:dynamicTreeStructure nodeChildren="#{Messages.nodeChildren}" /> <q:treeColumn id = "subjectColumn"> ... </q:treeColumn> <q:column id = "authorColumn"> ... </q:column> ... </q:treeTable> Note There are also two per-column attributes that are applicable only when TreeTable 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 teamdev.jsf.component.datatable.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. Fetching Data on TreeTable RenderingWhen the TreeTable 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 TreeTables. The display-only mode means that there is no UIInput, UICommand components and the checkbox column and selection features are disabled. If the TreeTable is not in display-only mode, the data is fetched twice just like in the standard DataTable component. Concurrent Data ModificationsThe 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 FootersThe 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 MessageIf 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-size:20pt"> <f:facet name="noDataMessage"> <h:outputText value="There is no data to display"> </f:facet> ... </q:treeTable> SortingThe 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 attribute 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. 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> 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:treeTable var="node"> <q:dynamicTreeStructure nodeChildren="#{treeTableBean.nodeChildren}"/> <q:treeColumn> <f:facet name="header"> <h:outputText value="name"/> </f:facet> <h:outputText value="#{node.name}"/> </q:treeColumn> <q:columns value="#{treeTableBean.dynamicColumns}" var="col" sortingExpression="#{node.dynamicColumns[col]}"> <f:facet name="header"> <h:outputText value="#{col}"/> </f:facet> <h:inputText value="#{node.dynamicColumns[col]}"/> </q:columns> </q:treeTable> 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 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. 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. 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. Sorting-Related StylesIt is possible to highlight headers of sortable columns using the following styling attributes:
The styles different parts of a sorted column can be customized using the following attributes:
FilteringThe 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 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:
In addition to the unique column values, the "comboBox" and "dropDownField" filter components provide three predefined filter 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 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 TextFilterCriterion, EmptyRecordsCriterion or 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> 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:treeTable var="node"> <q:dynamicTreeStructure nodeChildren="#{treeTableBean.nodeChildren}"/> <q:treeColumn> <f:facet name="header"> <h:outputText value="name"/> </f:facet> <h:outputText value="#{node.name}"/> </q:treeColumn> <q:columns value="#{treeTableBean.dynamicColumns}" var="col" filterExpression="#{node.dynamicColumns[col]}" filterKind="dropDownField"> <f:facet name="header"> <h:outputText value="#{col}"/> </f:facet> <h:inputText value="#{node.dynamicColumns[col]}"/> </q:columns> </q:treeTable> Filtering-Related StylesYou 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 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 SelectionThe 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 ModeTo 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:
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. If you don't what to let the user change the selection, 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:
You can apply a style to a selected row by using the style and styleClass attributes of the <q:singleNodeSelection> tag. Multiple Selection ModeTo 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 TreePath instances, respectively. Empty lists mean an empty selection. Note that if you want to change selection from the backing bean, the node data objects provided by the nodeDatas attribute should be serializable and correctly implement the equals and hashCode methods. 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> Using a Checkbox ColumnThe TreeTable 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 node data object. You can use it as an alternative of or in addition to multiple selection or to implement complicated selection models. To add a checkbox column to the TreeTable component, use the <q:checkboxColumn> tag. It has two attributes rowDatas and nodePaths which you should define as value-binding expressions that reference a list of node data objects and TreePath instances, respectively. Please note that the rowIndexes attribute is only applicable for the DataTable component. In addition, you can add a child <q:selectAllCheckbox> tag to the "header" or "footer" facets (or both) of the <q:checkboxColumn> (You can also add this tag to the Selection Column component). Note that the checkbox column imposes the same requirements on the data source as does the selection feature: Node data should be serializable and correctly implement the equals and hashCode methods, or the nodeKey attribute should be provided. It is also important to note that the checkbox column stores a list of selected nodes independently of the selection and independently of each other (when several checkbox columns are used in the same TreeTable 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:treeTable var="mesasage"> <q:checkboxColumn rowDatas="#{Messages.checkedMessages}"> <f:facet name="header"> <q:selectAllCheckbox /> </f:facet> </q:checkboxColumn> ... </q:treeTable> Dynamic Data LoadingThe TreeTable component supports dynamic data loading for such features as sorting, filtering, and node expansion, using Ajax. 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 component 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 Specifying the content of the "above" and "below" facetsThe "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:
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 NodesUsing 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 its nodes are collapsed. You can change this behavior by setting the expansionState attribute. You can specify the expansionState attribute right on the JSP page or as a value-binding expression that should be bound to the property of ExpansionState type. The ExpansionState is just an interface that has different implementations for different expansion states. The expansionState attribute can take one of the following values:
In addition to these three values, which can be set both right on the JSP page and when using value binding, there's one more value which can be set only with value binding. Specifying the expansionState attribute as an instance of the teamev.jsf.component.treetable.DynamicNodeExpansionState class denotes all other expansion states of the TreeTable component which cannot be described with the above three types of values (for example, all nodes are collapsed except one). This class has two constructors: a no-args constructor and a constructor receiving an instance of ExpansionState to serve as a default expansion state. While the previously described classes represent the "static" expansion state and it's not possible to specify an expansion state of individual nodes for them, DynamicNodeExpansionState has the setNodeExpanded(TreePath keyPath, boolean expanded) method which can be used to flexibly customize the expansion state on a per-node basis. 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 be specified right on the JSP page or as a value-binding expression that references the PreloadedNodes class. Like the ExpansionState class, it's just an interface that has different implementations. The preloadedNodes attribute can take one of the following values:
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 expanded nodes. Keyboard NavigationThe 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:
In addition, the user can select not contiguous row ranges by pressing the Ctrl key and clicking rows with the mouse. Customizing Individual Rows and CellsIn addition to an ability to customize all rows in the TreeTable'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:treeTable> 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 root nodes green: <q:treeTable var="message" nodeLevelVar="level"> <q:row condition="#{level == 0}" style="color:green;"/> ... </q:treeTable> 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.
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 don't have children. <q:treeTable var="message" nodeHasChildrenVar="nodeHasChildren"> <q:row condition="#{nodeHasChildren == false}"> <q:cell style="color:gray;"/> <q:cell style="color:silver;"/> </q:row> ... <q:column>...</q:column> <q:column>...</q:column> ... </q:treeTable> 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:treeTable var="message" nodeLevelVar="nodeLevel"> <q:row condition="#{nodeLevel > 0}"> <q:cell columnIds="subjectColumn, fromColumn" style="text-align:left; color:green;"/> </q:row> ... <q:column id="subjectColumn">...</q:column> ... <q:column id="fromColumn">...</q:column> ... </q:treeTable> 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 condition: <q:treeTable var="message" nodeLevelVar="nodeLevel"> <q:row condition="#{nodeLevel > 0}"> <q:cell column="condition:#{columnIndex == 0}" style="text-align:left; color:green;"/> </q:row> ... </q:treeTable> Note 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 CellsThe QuipuKit TreeTable 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: Below is an example with a TreeTable consisting of six columns. The cells in the root nodes are merged across all six columns: <q:treeTable var="message" nodeLevelVar="nodeLevel"> <q:row condition="#{nodeLevel == 0}"> <q:cell span="6"/> </q:row> ... </q:treeTable> 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 StylesSection StylesBy default, the TreeTable component uses a default style. To turn 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. Also, the <q:column>, <q:selectionColumn> and <q:treeColumn> tags have the width, align and valign attributes that are rendered onto the <col> tag of the respective column. The TreeTable component provides a number of style attributes for customizing its header, body, and footer sections.
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 StylesThe 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:
Styles ExampleThe following example shows the styles applied to the sections of the 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 StylesA 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:
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. 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. Other StylesThe TreeTable component supports 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 StylesYou 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.
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" filterRowSeparator="1px dotted black" footerHorizSeparator="2px solid gray" headerVertSeparator="1px solid gray" footerVertSeparator="1px solid gray"> <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:
Column Group SeparatorsThe 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:
Conditional StylesWhile all of the styles descr | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||