Introduction
The Apache Trinidad component is used to display a list of structured data. For example, if we have a data structure called Person that has two properties - firstname and lastname, we could use a Table with two columns - one for firstname, and the other for lastname - to display a list of Person objects. The Table component is similar to the standard UIData component in JSF, but includes a number of extra features, including support for identifying rows by key (instead of by index), built-in support for paging through large models, sorting the model, and selecting single or multiple items in the model.The Table Model
The Apache Trinidad component uses a model to access the data in the underlying list. The specific model class is org.apache.myfaces.trinidad.model.CollectionModel. You may also use other model instances, e.g., java.util.List, array, and javax.faces.model.DataModel. The Table will automatically convert the instance into a CollectionModel. To access a particular row in the list, first make that row current, and then call the getRowData() method on the Table. To make a row current, call the setRowIndex(...) method (on the Table) with the appropriate index into the list. Alternatively, call the setRowKey(...) method with the appropriate rowKey. To obtain the total number of rows in the list, call the getRowCount() method on the Table. In the case where the model does not yet know the total number of rows that are available, getRowCount() will return -1. The Table has an isRowAvailable() method that returns true if the current row ( see setRowIndex(...) ) is available. This method is especially useful when the total number of rows is unknown.Columns
The immediate children of a Table component must all be <tr:column> components. Each visible ADF Column component creates a separate column in the Table.Headers
Use the "header" facet on a Column to create the column header. You can also use the "headerText" attribute to set the column header. The following example creates a two-column table with the column headers - "Firstname" and "Lastname":<tr:table> <tr:column> <f:facet name="header"> <tr:outputText value="Firstname"/> </f:facet> ... </tr:column> <tr:column headerText="Lastname"> ... </tr:column> </tr:table>
Note that both ADF Faces and JSF HTML tags can be used inside of the ADF table.
Data
The child components of each Column display the data for each row in that column. The Column does not create child components per row; instead, each child is repeatedly rendered (stamped) once per row. Because of this stamping behavior, some components many not work inside the table. Anything that is just pure output, with no behavior, will work without problems, as will components that don't "mutate" even as they deliver events (for example, command components are fine). Components that mutate their state are affected, but any that implement EditableValueHolder are supported (this includes all form input controls from the JSF specification as well as ADF Faces input controls), as are UIXShowDetail components. As each row is stamped, the data for the current row ( see getRowData() ) is copied into an EL reachable property. The name of this property is defined by the var property on the Table. Once the Table has completed rendering, this property is removed (or reverted back to its previous value). In the following example, the data for each row is placed under the EL property "row". Each Column displays the data for each row by getting further properties from the "row" property:<tr:table var="row" value="#{myBean.allEmployees}"> <tr:column> <tr:outputText value="#{row.firstname}"/> </tr:column> <tr:column> tr:outputText value="#{row.lastname}"/> </tr:column> </tr:table>
Formatting
The Column component supports the following attributes related to formatting:
- align
- The type of alignment to use for this column. The legal values are "left", "right", "start", "end" and "center". Use "left" for left-justified, "right" for right-justified, and "center" for center-justified columns. For BiDi columns use "start" and "end". Use "start" (instead of "left") to left-align columns in a left-to-right locale, and right-align columns in a right-to-left locale. Similarly, use "end" (instead of "right") to right-align columns in a left-to-right locale, and left-align columns in a right-to-left locale.
- width
- The width of this column, e.g. "100px".
- noWrap
- Controls whether long lines of text in the column data should be wrapped.
Column Groups
<tr:column> tags can be nested to produce groups of columns. The header of a column group spans across all the columns it contains. The following example creates a column group that has the header "Name" and contains two sub columns with headers "First" and "Last":<tr:table var="row" value="#{myBean.employees}"> <tr:column headerText="Name"> <tr:column headerText="First"> <tr:outputText value="#{row.firstname}"/> </tr:column> <tr:column headerText="Last"> tr:outputText value="#{row.lastname}"/> </tr:column> </tr:column> </tr:table>
Range Navigation
When the list being displayed by a Table is huge, you can enable the Table to break up the list into ranges and display a single range at a time. Range controls are provided on the Table to let the user scroll to the next range, or to go back to the previous range. If the total size of the list is known, a control to let the user jump directly to a particular part of the list is also provided on the Table. Use the Table attributes "rows" and "first" to control the range navigation feature. The maximum number of rows to display in a single range is controlled by the "rows" attribute, which defaults to a reasonable size (e.g., 25). To disable range navigation (and display all the rows on one page) set this attribute to 0. In the following example, the maximum number of rows to display per range is set to 10:<tr:table rows="10" ...>
RangeChangeEvent
When the user changes the range (being displayed in the Table), the Table generates a RangeChangeEvent. This event includes the index (based at zero) of the row that should now be at the top of the range. The Table responds to this event by automatically changing the value of the "first" attribute to this index. In some cases it is necessary to know when the user changes the range on the Table (e.g., when the user navigates forward it might be necessary to release any cached data created for a previous range). To receive notifications of when the user changes the range, a RangeChangeListener instance should be registered with the Table. This is done by calling the addRangeChangeListener method, or by using the rangeChangeListener MethodBinding on the Table. These listeners are called after the Table has changed the "first" attribute in response to the event.Displaying Details
You can configure the Table to display or hide additional details of a particular row in response to a user gesture. When the details feature is enabled, a new column containing a toggle (per row) will render in the Table. When a toggle is activated, the details for that row are displayed. When a toggle is deactivated, the details for the row are hidden. The user can also display or hide the details for all rows at the same time (the controls for this feature are enabled by setting the "allDetailsEnabled" property to true.) To enable the details feature set the "detailStamp" facet on the Table. Place the components that are used to show the details (of a row), inside this facet. In the following example, the Person's age is displayed in the details section:<tr:table var="row" value="#{myBean.allEmployees}"> <f:facet name="detailStamp"> <tr:outputText value="#{row.age}"/> </f:facet> </tr:table>
RowDisclosureEvent
When the user hides or shows the details of a row, the Table generates a RowDisclosureEvent. This event has properties that return which rows were disclosed and which were undisclosed. The Table responds to this by expanding or collapsing the details of those rows.You can register custom RowDisclosureListener instances (that can do post processing) on the Table component.
Selection
The selection feature of a Table lets the user select one or more rows in the list. The user can then perform some operation on the selected rows by activating an appropriate ActionSource component (e.g., by clicking on an ADF CommandButton). Use the "rowSelection" attribute on the Table to enable the selection feature (see the examples below).
There are two types of selection - single and multiple. The type of selection is determined by the value of the "selection" attribute. Use the value "single" to enable single selection, and "multiple" to enable multiple selection.
The current selection of rows on the Table can be programmatically inspected and modified via the RowKeySet object obtained by calling getSelectedRowKeys() on the Table. To programmatically change a selection, add or remove rowKeys from this Set. Alternatively, the appropriate row can be made current by calling setRowIndex(...) or setRowKey(...) on the Table, and then the selection of that row may be changed by calling add() or remove() on the RowKeySet.Selection Example
In the following example, the performDelete method is called when the "Delete" button is clicked.<tr:table binding="#{mybean.table}" rowSelection="multiple" ...> <f:facet name="footer"> <tr:commandButton text="Delete" actionListener="#{mybean.performDelete}"/> </f:facet> ... </tr:table>
public void performDelete(ActionEvent action) { UIXTable table = getTable(); Iterator selection = table.getSelectedRowKeys().iterator(); Object oldKey = table.getRowKey(); while(selection.hasNext()) { Object rowKey = selection.next(); table.setRowKey(rowKey); MyRowImpl row = (MyRowImpl) table.getRowData(); row.markForDeletion(); } // restore the old key: table.setRowKey(oldKey); } // Binding methods for access to the table. public void setTable(UIXTable table) { _table = table; } public UIXTable getTable() { return _table; } private UIXTable _table;
SelectionEvent
The <tr:table> component triggers SelectionEvents when the selection state is changed. The SelectionEvent reports which rows were just deselected and which rows were just selected. Listeners for this event may be registered on the table using the "selectionListener" attribute or by adding the listener to the table using the "addSelectionListener" method.Sorting
The Table component supports sorting columns in ascending or descending order. A special UI indicator on a column header lets the user know that the column is sortable. When the user clicks on a column header to sort a previously unsorted column, the Table sorts the column data in ascending order. Subsequent clicks on the same header sort the data in the reverse order.
There are three requirements to enable sorting: the underlying table model must support sorting, the "sortProperty" and "sortable" attributes must be set on the column to enable the sort capability for that column.
To support sorting, the CollectionModel instance must implement the following methods:public boolean isSortable(String propertyName) public List getSortCriteria() public void setSortCriteria(List criteria)
<tr:table ...> <tr:column sortProperty="firstname" sortable="true"> <f:facet name="header"> <tr:outputText value="Firstname" /> </f:facet> ... </tr:column> <tr:column> <f:facet name="header" sortProperty="lastname" sortable="true"> <tr:outputText value="Lastname" /> </f:facet> ... </tr:column> </tr:table>
SortEvent
When the user clicks a sortable column header, the <tr:table> component generates a SortEvent. This event has a getSortCriteria() property that returns the criteria that the table must be sorted by.
The Table responds to this event by calling the setSortCriteria method on the underlying CollectionModel. Any registered SortListener instances will also be called.
Grid Lines and Banding
By default, the table draws both horizontal and vertical grid lines. These may be independently turned off by setting the "horizontalGridVisible" and/or "verticalGridVisible" attributes to "false". Banding is a technique where groups of rows (or columns) are displayed with alternating background colors. This helps to differentiate between adjacent groups of rows (or columns). The "rowBandingInterval" attribute on the Table controls how many consecutive rows form a row group (for the purposes of banding). If this is "0" all rows will have the same background color. If this is a positive number then adjacent row groups will have different background colors. The "columnBandingInterval" attribute on the Table controls how many columns form a column group (for the purposes of banding). If this is "0" all columns will have the same background color. If this is a positive number then adjacent column groups will have different background colors. In the following example, the row banding pattern is to have two rows with a light background, followed by two rows with a dark background. The pattern is repeated across all rows. Similarly the column banding pattern is to have alternating light/dark columns.<tr:table rowBandingInterval="2" columnBandingInterval="1" ...> ... </tr:table>