Oracle ADF Faces - Using the ADF Table Component
Introduction

The ADF Table 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 include s 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, selecting single or multiple items in the model, and toggling the display of details for particular items in the model.

The Table Model

The ADF Table component uses a model to access the data in the underlying list. The specific model class is oracle.adf.view.faces.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 < af: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. The following example creates a two-column table with the column headers - "Firstname" and "Lastname":

<af:table>
  <af:column>
    <f:facet name="header">
      <af:outputText value="Firstname"/>
    </f:facet>
    ...
  </af:column>
  <af:column>
    <f:facet name="header">
      <h:outputText value="Lastname"/>
    </f:facet>
    ...
  </af:column>
</af: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 r everted 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:

<af:table var="row" value="#{myBean.allEmployees}">
  <af:column>
    <af:outputText value="#{row.firstname}"/>
  </af:column>
  <af:column>
    af:outputText value="#{row.lastname}"/>
  </af:column>
</af:table>
        
Formatting

The Column component supports the following attributes related to formatting:

formatType
The type of formatting to use for this column. The legal values are "text", "number" and "icon", which describe columns that display text, numbers and buttons, respectively. Text columns are left-justified, number columns are right-justified, and button columns are center-justified.
gridVisible
Controls the display of a grid line on the left of the column.
width
The width of this column, e.g., "30%", "100px".
bandingShade
Determines what background color to use for this column. The legal values are "light" and "dark".
noWrap
Controls whether long lines of text in the column data should be wrapped.
headerNoWrap
Controls whether long lines of text in the column header should be wrapped.
separateRows
Controls whether each child of this column should be rendered in separate cells, or inside the same cell.

Column Groups

< af: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":

  <af:table var="row" value="#{myBean.employees}">
    <af:column>
      <f:facet name="header">
        <af:outputText value="Name"/>
      </f:facet>
      <af:column>
        <f:facet name="header">
          <af:outputText value="First"/>
        </f:facet>
        <af:outputText value="#{row.firstname}"/>
      </af:column>
      <af:column>
        <f:facet name="header">
          <af:outputText value="Last"/>
        </f:facet>
        af:outputText value="#{row.lastname}"/>
      </af:column>
    </af:column>
  </af:table>
          
Row Headers

Columns can be rendered as row headers by setting the "rowHeader" attribute on < column > to be true. Row header columns must be the first columns in a 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:

<af:table rows="10" ...>

The current range to display is controlled by the "first" attribute. This attribute is an index (based at zero) of a row in the list. Each range starts with the row identified by "first", and only contains as many rows as indicated by the "rows" attribute. Initially, the "first" attribute defaults to zero, which displays the range with the first row at the top.

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:

<af:table var="row" value="#{myBean.allEmployees}">
  <f:facet name="detailStamp">
    <af:outputText value="#{row.age}"/>
  </f:facet>
</af:table>
        

Usually, the default behavior of the Table (with respect to displaying and hiding details) is sufficient. In some cases, however, it might be desirable to programmatically display or hide the details for a particular row. This can be done via the RowKeySet object obtained from the Table by calling the getDisclosureState() method. First, make the relevant row current by calling setRowIndex(...) or setRowKey(...) on the Table, and then call add() or remove() on the RowKeySet object. Adding the row to the set displays the details of the row. Removing the row hides them.

DisclosureEvent

When the user hides or shows the details of a row, the Table generates a DisclosureEvent . This event has an isExpanded method that returns whether the user wants to show or hide the details of a particular row. That particular row is made current on the Table before the event is delivered. The Table responds to this by expanding or collapsing the details of that row.

You can register custom DisclosureListener instances (that can do post processing) on the Table component.

DisclosureAllEvent

When the user hides or shows the details of all rows, the Table generates a DisclosureAllEvent . This event has an isExpandAll method that returns whether the user wants to show or hide the details of all rows. The Table responds to this by expanding or collapsing all the detail rows.

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 "selection" facet 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 component defined as the "selection" facet. Use the < af:tableSelectOne > component to enable single selection, and < af:tableSelectMany > for multiple selection.

The current selection of rows on the Table can be programmatically inspected and modified via the RowKeySet object obtained by calling getSelectionState() on the Table. The rowKeys of the currently selected rows can be accessed via the getRowKeyIterator() method on the RowKeySet instance. To programmatically change a selection, the appropriate row must first be made current by calling setRowIndex(...) or setRowKey(...) on the Table. Then the selection of the row may be changed by calling add() or remove() on the RowKeySet .

Single Selection

You enable single selection by setting the < af:tableSelectOne > component as the "selection" facet on the Table. This component supports the "text" attribute, which is used to display instructions to the user. The children of this component are usually ActionSource components; these provide the actions available to the user after selecting a row.

<af:table ...>
  <f:facet name="selection">
    <af:tableSelectOne text="Select an item and click on a button">
      <af:commandButton text="Edit" action="..."/>
      <af:commandButton text="Delete" .../>
      <af:commandButton text="Copy" .../>
      <af:commandButton text="Cut" .../>
    </af:tableSelectOne>
  </f:facet>
</af:table>
        

Once the user makes a selection and clicks a button, the TableSelectOne component updates the RowKeySet obtained by calling getSelectionState() on the Table. The currently selected row is made current prior to calling the ActionListener associated with the activated button. This means that an action method on the selected row can easily be called, as shown in the following example:

<af:table var="row">
  <f:facet name="selection">
    <af:tableSelectOne>
      <af:commandButton text="Delete" action="#{row.markForDeletion}"/>
    </af:tableSelectOne>
  </f:facet>
</af:table>
        

In the example above, a method (on the selected row instance) with the following signature will be called:

public String markForDeletion()
          

Multiple Selection

Multiple selection is enabled by setting the < af:tableSelectMany > component as the "selection" facet on the Table. Like < af:tableSelectOne > this component supports the "text" attribute, which is used to display instructions to the user. The children of this component are usually ActionSource components; these provide the actions available to the user after selecting the rows.

<af:table ...>
  <f:facet name="selection">
    <af:tableSelectMany text="Make a selection and click on a button">
      <af:commandButton text="Delete"/>
      <af:commandButton text="Copy"/>
      <af:commandButton text="Cut"/>
    </af:tableSelectMany>
  </f:facet>
</af:table>
        

Once the user makes a selection and clicks a button, the TableSelectMany component updates the RowKeySet obtained by calling getSelectionState() on the Table prior to calling the ActionListener associated with the button. The ActionListener gets the selected rowKeys by calling getSelectionState().getRowKeyIterator() on the Table.

In the following example, the performDelete method is called when the "Delete" button is clicked.

<af:table binding="#{mybean.table}" ...>
  <f:facet name="selection">
    <af:tableSelectMany text="Make a selection and click on a button">
      <af:commandButton text="Delete" actionListener="#{mybean.performDelete}"/>
    </af:tableSelectMany>
  </f:facet>
</af:table>
        

The performDelete method iterates through all the selected rows and calls the markForDeletion() method on each one:

public void performDelete(ActionEvent action)
{
  UIXTable table = getTable();
  Iterator selection = table.getSelectionState().getRowKeyIterator();
  String oldKey = table.getRowKey();
  while(selection.hasNext())
  {
    String rowKey = (String) 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;
        

The above code sample will actually work with both < af:tableSelectOne > and < af:tableSelectMany > , though with < af:tableSelectOne > , at most a single row would ever be returned from the Iterator.

SelectionEvent

Both the < af:tableSelectOne > and the < af:tableSelectMany > components trigger SelectionEvents when the selection state of the table 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 "addSele ctionListener" 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)
        

If the underlying model is not a CollectionModel , the Table automatically examines the actual data to determine which properties are sortable. Any column that has data that implements java.lang.Comparable are sortable. This automatic support cannot be nearly as efficient as coding sorting directly into a CollectionModel (for instance, by translating the sort into an "ORDER BY" SQL clause), but is sufficient for small data sets.

To associate a column with a particular property-name to be used for sorting purposes, use the "sortProperty" attribute on the column. To enable the UI for sorting a particular column, set the "sortable" property to true .

In the following example, both columns are sortable. S orting the first column sorts by the "firstname" property; sorting the second column sorts by the "lastname" property.

<af:table ...>
  <af:column sortProperty="firstname" sortable="true">
    <f:facet name="header">
      <af:outputText value="Firstname" />
    </f:facet>
    ...
  </af:column>
  <af:column>
    <f:facet name="header" sortProperty="lastname" sortable="true">
      <af:outputText value="Lastname" />
    </f:facet>
    ...
  </af:column>
</af:table>
      
SortEvent

When the user clicks a sortable column header, the < af: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.

Banding

Banding is a technique where groups of rows (or columns) are displayed with alternating background colors. This helps to differentiate between adjacent rows (or columns).

The "banding" attribute on the Table controls the type of banding to use. The legal values are "row", "column" and "none". When "banding" is "row", adjacent rows have alternating background colors. When "banding" is "column", adjacent columns have alternating background colors. When "banding" is "none", banding is disabled. The default is "none".

When banding is enabled, the "bandingInterval" attribute controls the number of consecutive rows (or columns) that are colored the same. It defaults to "1".

Note that the above banding attributes on the Table are ignored when the "bandingShade" attribute is used on the Column (see Formatting ).

Copyright © 2003-2006, Oracle Corporation. All Rights Reserved.

E-mail this page
Printer View Printer View
Oracle Is The Information Company About Oracle | Oracle RSS Feeds | Careers | Contact Us | Site Maps | Legal Notices | Terms of Use | Privacy