12 Using Tables, Trees, and Other Collection-Based Components

This chapter describes how to display structured data in components that can iterate through collections of data and then display each row in the collection, using the ADF Faces table, tree and treeTable, listView, and carousel components. If your application uses the Fusion technology stack, then you can use data controls to create these components. SeeCreating ADF Databound Tables, Displaying Master-Detail Data, and Using More Complex Databound ADF Faces Components in Developing Fusion Web Applications with Oracle Application Development Framework.

This chapter includes the following sections:

About Collection-Based Components

The basic understanding of what is collection-based components is explained. The additional functionalities, such as Customizing the toolbar, Active Data and others, also can be used along with ADF table and tree components.

ADF Faces provides components that you can use to iterate through and display collections of structured data. Instead of containing a child component for each record to be displayed, and then binding these components to the individual records, these components are bound to a complete collection, and they then repeatedly render one component (for example an outputText component), by stamping the value for each record.

Structured data can be displayed as a simple table consisting of a number of rows and one column, using the ListView component, or multiple columns using the ADF Faces table component. Hierarchical data can be displayed either as tree structures using ADF Faces tree component, or in a table format, using ADF Faces tree table component. A collection of images can be displayed in a carousel component. Figure 12-1 shows the ADF Faces collection-based components.

Figure 12-1 ADF Faces Collection-Based Components

Description of Figure 12-1 follows
Description of "Figure 12-1 ADF Faces Collection-Based Components"

Tip:

When you do not want to use a table, but still need the same stamping capabilities, you can use the iterator tag. For example, say you want to display a list of periodic table elements, and for each element, you want to display the name, atomic number, symbol, and group. You can use the iterator tag as shown in the following example.

<af:iterator var="row" first="3" rows="3" varStatus="stat"     
             value="#{periodicTable.tableData}" >
  <af:outputText value="#{stat.count}.Index:#{stat.index} of
                                   #{stat.model.rowCount}"/>
  <af:outputText label="Element Name" value="#{row.name}"/>
  <af:outputText label="Atomic Number" value="#{row.number}"/>
  <af:outputText label="Symbol" value="#{row.symbol}"/>
  <af:outputText label="Group" value="#{row.group}"/>
</af:iterator>

Each child is stamped as many times as necessary. Iteration starts at the index specified by the first attribute for as many indexes specified by the row attribute. If the row attribute is set to 0, then the iteration continues until there are no more elements in the underlying data.

Collection-Based Component Use Cases and Examples

Collection-based components are used to display structured information. For example, as shown in Figure 12-2, the Table tab in the File Explorer application uses a table to display the contents of the selected directory.

Figure 12-2 Table Component in the File Explorer Application

Description of Figure 12-2 follows
Description of "Figure 12-2 Table Component in the File Explorer Application"

Hierarchical data (that is data that has parent/child relationships), such as the directory in the File Explorer application, can be displayed as expandable trees using the tree component. Items are displayed as nodes that mirror the parent/child structure of the data. Each top-level node can be expanded to display any child nodes, which in turn can also be expanded to display any of their child nodes. Each expanded node can then be collapsed to hide child nodes. Figure 12-3 shows the file directory in the File Explorer application, which is displayed using a tree component.

Figure 12-3 Tree Component in the File Explorer Application

Description of Figure 12-3 follows
Description of "Figure 12-3 Tree Component in the File Explorer Application"

Hierarchical data can also be displayed using tree table components. The tree table also displays parent/child nodes that are expandable and collapsible, but in a tabular format, which allows the page to display attribute values for the nodes as columns of data. For example, along with displaying a directory's contents using a table component, the File Explorer application has another tab that uses the tree table component to display the contents, as shown in Figure 12-4.

Figure 12-4 Tree Table in the File Explorer Application

Description of Figure 12-4 follows
Description of "Figure 12-4 Tree Table in the File Explorer Application"

Like the tree component, the tree table component can show the parent/child relationship between items. And like the table component, the tree table component can also show any attribute values for those items in a column. Most of the features available on a table component are also available in tree table component.

You can add a toolbar and a status bar to tables, trees, and tree tables by surrounding them with the panelCollection component. The top panel contains a standard menu bar as well as a toolbar that holds menu-type components such as menus and menu options, toolbars and toolbar buttons, and status bars. Some buttons and menus are added by default. For example, when you surround a table, tree, or tree table with a panelCollection component, a toolbar that contains the View menu is added. This menu contains menu items that are specific to the table, tree, or tree table component.

Figure 12-5 shows the tree table from the File Explorer application with the toolbar, menus, and toolbar buttons created using the panelCollection component.

Figure 12-5 TreeTable with Panel Collection

Description of Figure 12-5 follows
Description of "Figure 12-5 TreeTable with Panel Collection"

The listView component is a light-weight table that allows you to display structured data in a list format. Unlike a table, it does not have columns, which allows you to easily present data in a variety of patterns, beyond a simple tabular layout.

The components that display the actual data are contained in a single child listItem component. Figure 12-6 shows a listView component that contains one child listItem component. The listItem component contains a mix of layout components, output components and button components.

Figure 12-6 The listView Component Uses listItem Components to Hold Data for Each Row

Description of Figure 12-6 follows
Description of "Figure 12-6 The listView Component Uses listItem Components to Hold Data for Each Row"

The listView component can also display hierarchical data. When a component that is bound to the parent data is placed in the groupHeaderStamp facet, that data is displayed in a header. Figure 12-7 shows how the alphabet letters, which are the parent data, are displayed in headers, while the child personnel data is displayed in rows below the parent.

Figure 12-7 Hierarchical Data Can be Displayed in Groups

Description of Figure 12-7 follows
Description of "Figure 12-7 Hierarchical Data Can be Displayed in Groups"

The carousel component displays a collection of images in a revolving carousel, as shown in Figure 12-8. Users can change the image at the front either by using the slider at the bottom or by clicking one of the auxiliary images to bring that specific image to the front.

Figure 12-8 The ADF Faces Carousel

Description of Figure 12-8 follows
Description of "Figure 12-8 The ADF Faces Carousel"

Additional Functionality for Collection-Based Components

You may find it helpful to understand other ADF Faces features before you implement your collection-based components. Additionally, once you have added a collection-based component to your page, you may find that you need to add functionality such as validation and accessibility. Following are links to other functionality that table and tree components can use.

  • Customizing the toolbar: You can customize the toolbar included in the panelCollection component, which provides menus, toolbars, and status bars for the table and tree table components. For information about menus, toolbars, and toolbar buttons, see Using Menus, Toolbars, and Toolboxes.

  • Geometry management of the table width: If the table is a child to a component that stretches its children, then this width setting will be overridden and the table will automatically stretch to fit its container. For information about how components stretch, see Geometry Management and Component Stretching.

  • Active data: If your application uses active data, then you can have the data in your tables and trees update automatically, whenever the data in the data source changes. See Using the Active Data Service in Developing Fusion Web Applications with Oracle Application Development Framework.

    Note:

    If you wish to use active data, and your application uses ADF Business Components, then your tables must conform to the following:

    • The table or tree is bound to homogeneous data which contains only a single attribute.

    • The table does not use filtering.

    • The tree component's nodeStamp facet contains a single outputText tag and contains no other tags.

  • Events: Collection-based components fire both server-side and client-side events that you can have your application react to by executing some logic. See Handling Events.

  • Partial page rendering: You may want a collection-based component to refresh to show new data based on an action taken on another component on the page. See Using the Optimized Lifecycle.

  • Personalization: Users can change the way the component displays at runtime (for example the user can reorder columns or change column widths), those values will not be retained once the user leaves the page unless you configure your application to allow user customization. For information, see Allowing User Customization on JSF Pages.

  • Accessibility: You can make your components accessible. See Developing Accessible ADF Faces Pages.

  • Automatic data binding: If your application uses the Fusion technology stack, then you can create automatically bound tables and trees based on how your ADF Business Components are configured. See Creating ADF Databound Tables and Displaying Master-Detail Data in Developing Web User Interfaces with Oracle ADF Faces.

Common Functionality in Collection-Based Components

Using the functionalities available with collection-based components you can perform many functionalities. Some of them are, display data in a row in an ADF table structure and in node in an ADF tree structure, or you can decide to deliver either one row or multiple rows of content to the client machine.

Collection-based component share many of the same functionality, such as how data is delivered and how data can be displayed and edited. It is important that you understand this shared functionality and how it is configured before you use these components.

Displaying Data in Rows and Nodes

Instead of containing a child component for each record to be displayed, and then binding these components to the individual records, collection-based components are bound to a complete collection, and they then repeatedly render one component (for example an outputText component) by stamping the value for each record. For example, say a table contains two child column components. Each column displays a single attribute value for the row using an output component and there are four records to be displayed. Instead of binding four sets of two output components to display the data, the table itself is bound to the collection of all four records and simply stamps one set of the output components four times. As each row is stamped, the data for the current row is copied into the var attribute on the table, from which the output component can retrieve the correct values for the row. For information about how stamping works, especially with client components, see Accessing Client Collection Components.

The following example shows the JSF code for a table whose value for the var attribute is row. Each outputText component in a column displays the data for the row because its value is bound to a specific property on the variable.

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

Collection-based components uses a CollectionModel class to access the data in the underlying collection. This class extends the JSF DataModel class and adds on support for row keys and sorting. In the DataModel class, rows are identified entirely by index. This can cause problems when the underlying data changes from one request to the next, for example a user request to delete one row may delete a different row when another user adds a row. To work around this, the CollectionModel class is based on row keys instead of indexes.

You may also use other model classes, such as java.util.List, array, and javax.faces.model.DataModel. If you use one of these other classes, the table component automatically converts the instance into a CollectionModel class, but without the additional functionality. For information about the CollectionModel class, see the MyFaces Trinidad Javadoc at http://myfaces.apache.org/trinidad/trinidad-1_2/trinidad-api/apidocs/index.html.

Note:

If your application uses the Fusion technology stack, then you can use data controls to create tables and the collection model will be created for you. See Creating ADF Databound Tables in Developing Web User Interfaces with Oracle ADF Faces.

Content Delivery

The collection components are virtualized, meaning not all the rows that are there for the component on the server are delivered to and displayed on the client. You configure collection components to fetch a certain number of rows at a time from your data source. The data can be delivered to the components immediately upon rendering, when it is available, or lazily fetched after the shell of the component has been rendered (by default, the components fetch data when it is available), as specified by the setting the ContentDelivery attribute on the component.

With immediate delivery, the data is fetched during the initial request. With lazy delivery, when a page contains one or more collection components, the page initially goes through the standard lifecycle. However, instead of fetching the data during that initial request, a special separate partial page rendering (PPR) request is run, and the number of rows set as the value of the fetch size for the component is then returned. Because the page has just been rendered, only the Render Response phase executes for the components, allowing the corresponding data to be fetched and displayed. When a user's actions cause a subsequent data fetch (for example scrolling in a table for another set of rows), another PPR request is executed.

When content delivery is configured to be delivered when it is available, the framework checks for data availability during the initial request, and if it is available, it sends the data to the component and inlines it for rendering. If it is not available, the data is loaded during the separate PPR request, as it is with lazy delivery. Note that in JDeveloper releases prior to 12.2.1.0, two separate requests are required to send the data and to inline the data upon rendering the component. If you prefer the content delivery performance of an earlier release, you can set the ContentDelivery attribute to lazy; this will force inlining of the data only during a subsequent.

Note:

If your application does not use the Fusion technology stack, then you must explicitly add support for whenAvailable to your CollectionModel implementation. For an example, see the WhenAvailableData.java managed bean in the Faces demo application.

If your application does use the Fusion technology stack, then the CollectionModel implementation created for you automatically uses these APIs.

Performance Tip:

Lazy delivery should be used when a data fetch is expected to be an expensive (slow) operation, for example, slow, high-latency database connection, or fetching data from slow nondatabase data sources like web services. Lazy delivery should also be used when the page contains a number of components other than a table, tree, or tree table. Doing so allows the initial page layout and other components to be rendered first before the data is available.

Immediate delivery should be used if the table, tree, or tree table is the only context on the page, or if the component is not expected to return a large set of data. In this case, response time will be faster than using lazy delivery (or in some cases, simply perceived as faster), as the second request will not go to the server, providing a faster user response time and better server CPU utilizations. Note however that only the number of rows configured to be the fetch block will be initially returned. As with lazy delivery, when a user's actions cause a subsequent data fetch, the next set of rows are delivered.

When available delivery provides the additional flexibility of using immediate when data is available during initial rendering or falling back on lazy when data is not initially available. Starting in the JDeveloper 12.2.1.0 release, when available is the default delivery content delivery mode.

The number of rows that are displayed on the client are just enough to fill the page as it is displayed in the browser. More rows are fetched as the user scrolls the component vertically (or if configured to page instead of scroll, when the user navigates to another set of rows). The fetchSize attribute determines the number of rows requested from the client to the server on each attempt to fill the component. For a table, the default value is 25. So if the height of the table is small, the fetch size of 25 is sufficient to fill the component. However, if the height of the component is large, there might be multiple requests for the data from the server. Therefore, the fetchSize attribute should be set to a higher number. For example, if the height of the table is 600 pixels and the height of each row is 18 pixels, you will need at least 45 rows to fill the table. With a fetchSize of 25, the table has to execute two requests to the server to fill the table. For this example, you would set the fetch size to 50.

However, if you set the fetch size too high, it will impact both server and client. The server will fetch more rows from the data source than needed and this will increase time and memory usage. On the client side, it will take longer to process those rows and attach them to the component.

Performance Tip:

Reduce fetchSize whenever possible.

By default, on a desktop device, tables render a scroll bar that allows the users to scroll through the rows of data. Instead, when you want to configure the table to be paginated, you can set the scrollPolicy attribute to page. A paginated table displays a footer that allows the user to jump to specific pages of rows, as shown in Figure 12-9.

When the viewport is too narrow to display the complete footer, the table displays a compact footer that shows only the page currently displayed and the navigation buttons, as shown in Figure 12-10.

Figure 12-10 Paginated Table in Compact Mode

Description of Figure 12-10 follows
Description of "Figure 12-10 Paginated Table in Compact Mode"

Note:

By default, on tablet devices, tables are rendered to display the table as paginated and therefore do not display a scroll bar. If instead, you want to enable scroll bars so the table automatically loads the next set of rows when the user scrolls to the bottom of the table, you can set the scrollPolicy attribute to scroll. This option on tablets results in a behavior called implicit high-water mark scrolling and closely resembles the way virtualized touch scrolling (scrolling in both horizontal and vertical directions) behaves on tablet devices. Regular virtualized scrolling which results from setting scrollPolicy to scroll on a desktop machine is not implemented on tablets due to performance problems with virtualized scrolling of table data on tablets. You can, however, customize the caching behavior of implicit high-water mark scrolling by specifying the number of rows to cache to minimize database round-trips by setting a value for the maxClientRows attribute.

As with a table configured to scroll, the number of rows on a page is determined by the fetchSize attribute.

Note:

By default, if you configure your tables to use scroll bars, on iOS operating systems, the scroll bars appear only when you mouseover the content. You can configure your application so that this same behavior occurs on other operating systems as well, by setting the oracle.adf.view.rich.table.scrollbarBehavior parameter in the web.xml file. See Scrollbar Behavior in Tables.

Note:

You can hide the scroll bar using the -tr-overflow-style: autohiding-scrollbar skinning property. For example:

af|table {
  -tr-overflow-style: autohiding-scrollbar
}

For information about skins, see Customizing the Appearance Using Styles and Skins.

You can also configure the set of data that will be initially displayed using the displayRow attribute. By default, the first record in the data source is displayed in the top row or node and the subsequent records are displayed in the following rows or nodes. You can also configure the component to first display the last record in the source instead. In this case, the last record is displayed in the bottom row or node of the component, and the user can scroll up to view the preceding records. Additionally, you can configure the component to display the selected row. This can be useful if the user is navigating to the component, and based on some parameter, a particular row will be programmatically selected. When configured to display the selected row, that row will be displayed at the top of the table and the user can scroll up or down to view other rows.

Note:

You cannot use JavaScript to dynamically size a table or tree. The height of tables, trees and treetables is set the first time they are rendered and cannot be changed using JavaScript APIs.

Row Selection

You can configure selection to be either for no rows, for a single row, or for multiple rows using the rowSelection attribute (the carousel component does not allow multiple row selection). This setting allows you to execute logic against the selected rows. For example, you may want users to be able to select a row in a table or a node in a tree, and then to click a button that navigates to another page where the data for the selected row is displayed and the user can edit it.

Note:

If you configure your component to allow multiple selection, users can select one row and then press the shift key to select another row, and all the rows in between will be selected. This selection will be retained even if the selection is across multiple data fetch blocks. Similarly, you can use the Ctrl key to select rows that are not next to each other.

For example, if you configure your table to fetch only 25 rows at a time, but the user selects 100 rows, the framework is able to keep track of the selection.

When the selected row (or node) of a component changes, the component triggers a selection event. This event reports which rows were just deselected and which rows were just selected. While the components handle selection declaratively, if you want to perform some logic on the selected rows, you need to implement code that can access those rows and then perform the logic. You can do this in a selection listener method on a managed bean. See What You May Need to Know About Performing an Action on Selected Rows in Tables.

Performance Tip:

Users can navigate through the table using a mouse and the scrollbar, or using the up and down arrow keyboard keys. By default, a selection event is immediately fired when the user clicks a row. If the user is navigating through the rows using the arrow keys, this means that a selection event will be fired for each row, as the user navigates.

If you expect users to navigate through the table using the keys, you can set the delaySelectionEvent attribute to true, so that there is a 300 millisecond delay before the selection event is fired. If the user navigates to another row within the 300 milliseconds, the selection event is canceled.

Editing Data in Tables, Trees, and Tree Tables

You can choose the component used to display the actual data in a table, tree, or tree table. For example, you may want the data to be read-only, and therefore you might use an outputText component to display the data. Conversely, if you want the data to be able to be edited, you might use an inputText component, or if choosing from a list, one of the SelectOne components. All of these components are placed as children to the column component (in the case of a table and tree table) or within the nodeStamp facet (for a tree).

When you decide to use components whose value can be edited to display your data, you have the option of having the table, tree, or tree table either display all rows as available for editing at once, or display all but the currently active row as read-only using the editingMode attribute. For example, Figure 12-11 shows a table whose rows can all be edited. The page renders using the components that were added to the page (for example, inputText, inputDate, and inputComboBoxListOfValues components).

Figure 12-11 Table Whose Rows Can All Be Edited

Description of Figure 12-11 follows
Description of "Figure 12-11 Table Whose Rows Can All Be Edited"

Figure 12-12 shows the same table (that is, it uses inputText, inputDate, and inputComboBoxListOfValues components to display the data), but configured so that only the active row displays the editable components, by setting editingMode to clickToEdit. Users can then click on another row to make it editable (only one row is editable at a time). Note that outputText components are used to display the data in the noneditable rows, even though the same input components as in Figure 12-11 were used to build the page. The only row that actually renders those components is the active row.

Note:

When you set editingMode to readOnly , all the components in the table will be rendered as read only, including input components. Also when the entire table is selected, the editingMode will be set to readOnly.

Figure 12-12 Table Allows Only One Row to Be Edited at a Time

Description of Figure 12-12 follows
Description of "Figure 12-12 Table Allows Only One Row to Be Edited at a Time"

The currently active row is determined by the activeRowKey attribute on the table. By default, the value of this attribute is the first visible row of the table. When the table (or tree or tree table) is refreshed, that component scrolls to bring the active row into view, if it is not already visible. When the user clicks on a row to edit its contents, that row becomes the active row.

When you allow only a single row (or node) to be edited, the table (or tree or tree table) performs PPR when the user moves from one row (or node) to the next, thereby submitting the data (and validating that data) one row at a time. When you allow all rows to be edited, data is submitted whenever there is an event that causes PPR to typically occur, for example scrolling beyond the currently displayed rows or nodes.

Note:

Trees and tables support browser copy and paste. When you mouse over a text field that can be copied, the cursor displays an I-bar. When you click the mouse to copy the text, that row becomes selected.

Not all editable components make sense to be displayed in a click-to-edit mode. For example, those that display multiple lines of HTML input elements may not be good candidates. These components include:

  • SelectManyCheckbox

  • SelectManyListBox

  • SelectOneListBox

  • SelectOneRadio

  • SelectManyShuttle

Performance Tip:

For increased performance during both rendering and postback, you should configure your table to allow editing only to a single row.

When you elect to allow only a single row to be edited at a time, the page will be displayed more quickly, as output components tend to generate less HTML than input components. Additionally, client components are not created for the read-only rows. Because the table (or tree, or tree table) performs PPR as the user moves from one row to the next, only that row's data is submitted, resulting in better performance than a table that allows all cells to be edited, which submits all the data for all the rows in the table at the same time. Allowing only a singe row to be edited also provides more intuitive validation, because only a single row's data is submitted for validation, and therefore only errors for that row are displayed.

Using Popup Dialogs in Tables, Trees, and Tree Tables

You can configure your table, tree, or tree table so that popup dialogs will be displayed based on a user's actions. For example, you can configure a popup dialog to display some data from the selected row when the user hovers the mouse over a cell or node. You can also create popup context menus for when a user right-clicks a row in a table or tree table, or a node in a tree. Additionally, for tables and tree tables, you can create a context menu for when a user right-clicks anywhere within the table, but not on a specific row.

Tables, trees, and tree tables all contain the contextMenu facet. You place your popup context menu within this facet, and the associated menu will be displayed when the user right-clicks a row. When the context menu is being fetched on the server, the components automatically establish the currency to the row for which the context menu is being displayed. Establishing currency means that the current row in the model for the table now points to the row for which the context menu is being displayed. In order for this to happen, the popup component containing the menu must have its contentDelivery attribute set to lazyUncached so that the menu is fetched every time it is displayed.

Tip:

If you want the context menu to dynamically display content based on the selected row, set the popup content delivery to lazyUncached and add a setPropertyListener tag to a method on a managed bean that can get the current row and then display data based on the current row:

<af:tree value="#{fs.treeModel}" 
         contextMenuSelect="false" var="node" ..>
  <f:facet name="contextMenu">
    <af:popup id="myPopup" contentDelivery="lazyUncached">
      <af:setPropertyListener from="#{fs.treeModel.rowData}"
               to="#{dynamicContextMenuTable.currentTreeRowData}"
               type="popupFetch" />
      <af:menu>
       <af:menu text="Node Info (Dynamic)">
         <af:commandMenuItem actionListener=
           "#{dynamicContextMenuTable.alertTreeRowData}" 
           text=
     "Name - #{dynamicContextMenuTable.currentTreeRowData.name}" />
         <af:commandMenuItem actionListener=
           "#{dynamicContextMenuTable.alertTreeRowData}" 
           text=
     "Path - #{dynamicContextMenuTable.currentTreeRowData.path}" />
         <af:commandMenuItem actionListener=
           "#{dynamicContextMenuTable.alertTreeRowData}" 
           text="Date -
     #{dynamicContextMenuTable.currentTreeRowData.lastModified}" />
       </af:menu>
    </af:menu>
  </af:popup>
  </f:facet>
...
</af:tree>

The code on the backing bean might look something like this:

public class DynamicContextMenuTableBean
{
  ...
  public void setCurrentTreeRowData(Map currentTreeRowData)
  {
    _currentTreeRowData = currentTreeRowData;
  }
 
  public Map getCurrentTreeRowData()
  {
    return _currentTreeRowData;
  }
 
  private Map _currentTreeRowData;
}

Tables and tree tables contain the bodyContextMenu facet. You can add a popup that contains a menu to this facet, and it will be displayed whenever a user clicks on the table, but not within a specific row.

For information about creating context menus, see Declaratively Creating Popups.

Accessing Client Collection Components

With ADF Faces, the contents of collection-based components are rendered on the server. There may be cases when the client needs to access that content on the server, including:

  • Client-side application logic may need to read the row-specific component state. For example, in response to row selection changes, the application may want to update the disabled or visible state of other components in the page (usually menu items or toolbar buttons). This logic may be dependent on row-specific metadata sent to the client using a stamped inputHidden component. In order to enable this, the application must be able to retrieve row-specific attribute values from stamped components.

  • Client-side application logic may need to modify row-specific component state. For example, clicking a stamped command link in a table row may update the state of other components in the same row.

  • The peer may need access to a component instance to implement event handling behavior (for information about peers, see About Using ADF Faces Architecture). For example, in order to deliver a client-side action event in response to a mouse click, the AdfDhtmlCommandLinkPeer class needs a reference to the component instance which will serve as the event source. The component also holds on to relevant state, including client listeners as well as attributes that control event delivery behavior, such as disabled or partialSubmit.

Because there is no client-side support for EL in the ADF Faces framework, nor is there support for sending entire table models to the client, the client-side code cannot rely on component stamping to access the value. Instead of reusing the same component instance on each row, a new JavaScript client component is created on each row (assuming any component must be created at all for any of the rows).

Therefore, to access row-specific data on the client, you need to use the stamped component itself to access the value. To do this without a client-side data model, you use a client-side selection change listener. For detailed instructions, see Accessing Selected Values on the Client from Collection-Based Components.

Geometry Management for the Table, Tree, and Tree Table Components

By default, when tables, trees, and tree tables are placed in a component that stretches its children (for example, a panelCollection component inside a panelStretchLayout component), the table, tree, or tree table will stretch to fill the existing space. However, in order for the columns to stretch to fit the table, you must specify a specific column to stretch to fill up any unused space, using the columnStretching attribute. Otherwise, the table will only stretch vertically to fit as many rows as possible. It will not stretch the columns, as shown in Figure 12-13.

Figure 12-13 Table Stretches But Columns Do Not

Description of Figure 12-13 follows
Description of "Figure 12-13 Table Stretches But Columns Do Not"

When placed in a component that does not stretch its children (for example, in a panelCollection component inside a panelGroupLayout component set to vertical), by default, a table width is set to 300px (27.27em units which translates to 300px for an 11px font setting) and the default fetch size is set to return 25 rows, as shown in Figure 12-14.

Figure 12-14 Table Does Not Stretch

Description of Figure 12-14 follows
Description of "Figure 12-14 Table Does Not Stretch"

When you place a table in a component that does not stretch its children, you can control the height of the table so that is never more than a specified number of rows, using the autoHeightRows attribute. When you set this attribute to a positive integer, the table height will be determined by the number of rows set. If that number is higher than the fetchSize attribute, then only the number of rows in the fetchSize attribute will be returned. You can set autoHeightRows to -1 (the default), to turn off auto-sizing.

Auto-sizing can be helpful in cases where you want to use the same table both in components that stretch their children and those that don't. For example, say you have a table that has 6 columns and can potentially display 12 rows. When you use it in a component that stretches its children, you want the table to stretch to fill the available space. If you want to use that table in a component that doesn't stretch its children, you want to be able to "fix" the height of the table. However, if you set a height on the table, then that table will not stretch when placed in the other component. To solve this issue, you can set the autoHeightRows attribute, which will be ignored when in a component that stretches, and will be honored in one that does not.

Note:

The default value for the autoHeightRows attribute is handled by the DEFAULT_DIMENSIONS web.xml parameter. If you always want table components to be stretched when the parent can stretch, and to be the size of the fetchSize attribute when it cannot, set the DEFAULT_DIMENSIONS parameter instead of the autoHeightRows attribute. Set the autoHeightRows attribute when you want to override the global setting.

By default, DEFAULT_DIMENSIONS is set so that the value of autoHeightRows is -1 (the table will not stretch). See Geometry Management for Layout and Table Components.

On the other hand, when you do not want to set the autoHeightRows attribute but still want the table to stretch to fill up the empty vertical space, you can wrap the table with the panelStretchLayout component and use the viewportBottom attribute. However, you must explicitly use the AFStretchWidth styleClass and dimensionsFrom attributes with the viewPortBottom attribute. When you use this setup, the distance from the bottom of the panelStretchLayout to the bottom of the viewport matches the number of the pixels in the viewportBottom attribute, so that the table resizes to consume that empty space.

This setting is however not recommended as a long-term solution because the user will see the adjustment that takes place when the table is resized after the table displays at an initial size.

The following example shows the panelStretchLayout component with viewportBottom attribute code.

<af:panelGroupLayout id="scroller" layout="scroll">
 <af:panelStretchLayout id="wrapper" styleClass="AFStretchWidth"
  <dimensionsFrom="parent" viewportBottom="64">
  <f:facet name="center">
    <af:table ...>...</af:table>
  </f:facet>
 </af:panelStretchLayout>
</af:panelGroupLayout>

Displaying Data in Tables

The ADF tables with collection-based components can be formatted using various visual aids. Column data can be stored and sorted. Only partial page rendering happens when the page containing tables is requested by a client.

The immediate children of a table component must be column components. Each visible column component is displayed as a separate column in the table. Column components contain components used to display content, images, or provide further functionality. For information about the features available with the column component, see Columns and Column 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, the table uses stamping to render each row. Each child is stamped once per row, repeatedly for all the rows. As each row is stamped, the data for the current row is copied into a property that can be addressed using an EL expression. You specify the name to use for this property using the var property on the table. Once the table has completed rendering, this property is removed or reverted back to its previous value.

Because of this stamping behavior, some components may not work inside the column. Most components will work without problems, for example any input and output components. If you need to use multiple components inside a cell, you can wrap them inside a panelGroupLayout component. Components that themselves support stamping are not supported, such as tables within a table. For information about using components whose values are determined dynamically at runtime, see What You May Need to Know About Dynamically Determining Values for Selection Components in Tables.

You can use the detailStamp facet in a table to include data that can be optionally displayed or hidden. When you add a component to this facet, the table displays an additional column with an expand and collapse icon for each row. When the user clicks the icon to expand, the component added to the facet is displayed, as shown in Figure 12-15.

Figure 12-15 Extra Data Can Be Optionally Displayed

This image is described in the surrounding text.

When the user clicks on the expanded icon to collapse it, the component is hidden, as shown in Figure 12-16.

Figure 12-16 Extra Data Can Be Hidden

This image is described in the surrounding text.

For information about using the detailStamp facet, see Adding Hidden Capabilities to a Table.

Columns and Column Data

Columns contain the components used to display the data. As stated previously, only one child component is needed for each item to be displayed; the values are stamped as the table renders. Columns can be sorted, and you can configure whether the sort should be case-sensitive or case-insensitive. By default, it is case-sensitive.

Columns can also contain a filtering element. Users can enter a value into the filter and the returned data set will match the value entered in the filter. You can set the filter to be either case-sensitive or case-insensitive. If the table is configured to allow it, users can also reorder columns.

Columns have both header and footer facets. The header facet can be used instead of using the header text attribute of the column, allowing you to use a component that can be styled. The footer facet is displayed at the bottom of the column. For example, Figure 12-17 uses footer facets to display the total at the bottom of two columns. If the number of rows returned is more than can be displayed, the footer facet is still displayed; the user can scroll to the bottom row.

Figure 12-17 Footer Facets in a Column

This image is described in the surrounding text.

Formatting Tables

A table component offers many formatting and visual aids to the user. You can enable these features and specify how they can be displayed. These features include:

  • Row selection: By default, at runtime, users cannot select rows. If you want users to be able to select rows in order to perform some action on them somewhere else on the page, or on another page, then enable row selection for the table by setting the rowSelection attribute. You can configure the table to allow either a single row or multiple rows to be selected. For information about how to then programmatically perform some action on the selected rows, see What You May Need to Know About Performing an Action on Selected Rows in Tables.

  • Scrolling/Pagination: By default, on desktop devices, tables render a scroll bar that allows the user to scroll through all rows. On tablet devices, instead of a scroll bar, the table is paginated and displays a footer that allows the user to jump to specific pages of rows. You can change the default by setting the scrollPolicy attribute.

  • Table height: You can set the table height to be absolute (for example, 300 pixels), or you can determine the height of the table based on the number of rows you wish to display at a time by setting the autoHeightRows attribute. See Geometry Management for the Table, Tree, and Tree Table Components.

    Note:

    When table is placed in a layout-managing container, such as a panelSplitter component, it will be sized by the container and the autoHeightRows is not honored.

    Note:

    You cannot use JavaScript to dynamically size a table. The height of a table is set the first time is rendered and cannot be changed using JavaScript APIs.

  • Grid lines: By default, an ADF table component draws both horizontal and vertical grid lines. These may be independently turned off using the horizontalGridVisible and verticalGridVisible attributes.

  • Banding: Groups of rows or columns are displayed with alternating background colors using the columnBandingInterval attribute. This helps to differentiate between adjacent groups of rows or columns. By default, banding is turned off.

  • Column groups: Columns in a table can be grouped into column groups, by nesting column components. Each group can have its own column group heading, linking all the columns together. See Step 14 in How to Display a Table on a Page.

  • Editable cells: When you elect to use input text components to display data in a table, you can configure the table so that all cells can be edited, or so that the user must explicitly click in the cell in order to edit it. See Editing Data in Tables, Trees, and Tree Tables.

    Performance Tip:

    When you choose to have cells be available for editing only when the user clicks on them, the table will initially load faster. This may be desirable if you expect the table to display large amounts of data.

  • Column stretching: If the widths of the columns do not together fill the whole table, you can set the columnStretching attribute to determine whether or not to stretch columns to fill up the space, and if so, which columns should stretch. You can set the minimum width for columns, so that when there are many columns in a table and you enable stretching, columns will not be made smaller than the set minimum width. You can also set a width percentage for each column you want to stretch to determine the amount of space that column should take up when stretched.

    Note:

    If the total sum of the columns' minimum widths equals more than the viewable space in the viewport, the table will expand outside the viewport and a scrollbar will appear to allow access outside the viewport.

    Performance Tip:

    Column stretching is turned off by default. Turning on this feature may have a performance impact on the client rendering time when used for complex tables (that is, tables with a large amount of data, or with nested columns, and so on).

    Note:

    Columns configured to be row headers or configured to be frozen will not be stretched because doing so could easily leave the user unable to access the scrollable body of the table.

  • Column selection: You can choose to allow users to be able to select columns of data. As with row selection, you can configure the table to allow single or multiple column selection. You can also use the columnSelectionListener to respond to the ColumnSelectionEvent that is invoked when a new column is selected by the user. This event reports which columns were just deselected and which columns were just selected.

  • Column reordering: Users can reorder the columns at runtime by simply dragging and dropping the column headers. By default, column reordering is allowed, and is handled by a menu item in the panelCollection component. See Displaying Table Menus, Toolbars, and Status Bars.

  • Column freezing: You can configure the table so that columns can be frozen and so will not scroll out of view. Columns can be frozen on either the left or right side of the table. This is controlled by the freezeDirection attribute on the table. You choose the column to start the freeze using the frozen attribute on the column.

    Performance Tip:

    Use of column freezing increases the complexity of tables and can have a negative performance impact.

Formatting Columns

Each column component also offers many formatting and visual aids to the user. You can enable these features and specify how they can be displayed. These features include:

  • Column sorting: Columns can be configured so that the user can sort the contents by a given column, either in ascending or descending order using the sortable attribute. A sort icon on a column header lets the user know that the column can be sorted. The sort icon toggles depending on the sort order. Other columns that can be sorted displays the sort icon on the mouse hover. When the user clicks on the icon to sort a previously unsorted column, the column's content is sorted in ascending order. Subsequent clicks on the same header sort the content in the reverse order. For sortable columns, a space is reserved on the right of the column header for the sort icon.

    By default, sorting is case-sensitive. That is, abc would be sorted before ABC. You can configure the column so that instead, abc would be sorted the same as ABC, using the sortStrength attribute.

    In order for the table to be able to sort, the underlying data model must also support sorting. See What You May Need to Know About Programmatically Enabling Sorting for Table Columns.

  • Content alignment: You can align the content within the column to either the start, end, left, right, or center using the align attribute.

    Tip:

    Use start and end instead of left and right if your application supports multiple reading directions.

  • Column width: The width of a column can be specified as an absolute value in pixels using the width attribute. If you configure a column to allow stretching, then you can also set the width as a percentage.

  • Column spanning: You can configure a column to span across other columns using the colSpan attribute. Normally however, you use an EL expression as the value for the span, to enable only a certain cell in the column to actually span. For example, Figure 12-18 shows a tree table whose colSpan value resolves to span all rows to the right, only if the node is a parent node.

    Figure 12-18 Column Spans Only When the Node is a Parent

    Description of Figure 12-18 follows
    Description of "Figure 12-18 Column Spans Only When the Node is a Parent"
  • Line wrapping: You can define whether or not the content in a column can wrap over lines, using the noWrap attribute. By default, content will not wrap.

  • Row headers: You can define the left-most column to be a row header using the rowHeader attribute. When you do so, the left-most column is rendered with the same look as the column headers, and will not scroll off the page. Figure 12-19 shows how a table showing departments appears if the first column is configured to be a row header.

    Figure 12-19 Row Header in a Table

    Description of Figure 12-19 follows
    Description of "Figure 12-19 Row Header in a Table"

    If you elect to use a row header column and you configure your table to allow row selection, the row header column displays a selection arrow when a users hovers over the row, as shown in Figure 12-20.

    Figure 12-20 Selection Icon in Row Header

    Description of Figure 12-20 follows
    Description of "Figure 12-20 Selection Icon in Row Header"

For tables that allow multiple selection, users can mouse down and then drag on the row header to select a contiguous blocks of rows. The table will also autoscroll vertically as the user drags up or down.

In addition, when an error occurs that results in a message for a component in the row, the icon for the severity is displayed in the row header. If more than one message exists, the icon for the maximum severity is displayed. Figure 12-21 shows the error icon displayed in the row header because a date was entered incorrectly.

Figure 12-21 Row Headers Display Message Icons

Description of Figure 12-21 follows
Description of "Figure 12-21 Row Headers Display Message Icons"

Performance Tip:

Use of row headers increases the complexity of tables and can have a negative performance impact.

Tip:

While the user can change the way the table displays at runtime (for example the user can reorder columns or change column widths), those values will not be retained once the user leaves the page unless you configure your application to allow user customization. For information, see Allowing User Customization on JSF Pages.

How to Display a Table on a Page

You use the Create an ADF Faces Table dialog to add a table to a JSF page. You also use this dialog to add column components for each column you need for the table. You can also bind the table to the underlying model or bean using EL expressions.

Note:

If your application uses the Fusion technology stack, then you can use data controls to create tables and the binding will be done for you. SeeCreating ADF Databound Tables in Developing Fusion Web Applications with Oracle Application Development Framework.

Once you complete the dialog, and the table and columns are added to the page, you can use the Properties window to configure additional attributes of the table or columns, and add listeners to respond to table events. You must have an implementation of the CollectionModel class to which your table will be bound.

Before you begin:

It may be helpful to have an understanding of how the attributes can affect functionality. See SeeDisplaying Data in Tables.

You may also find it helpful to understand functionality that can be added using other ADF Faces features. See SeeAdditional Functionality for Collection-Based Components.

To display a table on a page:

  1. Create a Java class that extends the org.apache.myfaces.trinidad.model.CollectionModel class.

    Collection components use a CollectionModel class to access the data in the underlying collection. This class extends the JSF DataModel class, but is based on row keys instead of indexes to support underlying data changes. It also supports more advanced functionality, such as sorting.

    You may also use other model classes, such as java.util.List, array, and javax.faces.model.DataModel. If you use one of these other classes, the collection component automatically converts the instance into a CollectionModel class, but without any additional functionality. For information about the CollectionModel class, see the MyFaces Trinidad javadoc at http://myfaces.apache.org/trinidad/trinidad-1_2/trinidad-api/apidocs/index.html.

  2. In the Components window, from the Data Views panel, drag and drop a Table onto the page.

  3. Use the Create ADF Faces Table dialog to bind the table to any existing model you have. When you bind the table to a valid model, the dialog automatically shows the columns that will be created. You can then use the dialog to edit the values for the columns' header and value attributes, and choose the type of component that will be used to display the data. Alternatively, you can manually configure columns and bind at a later date. For help with the dialog, click Help or press F1.

    Note:

    If you are using an inputText component to display a Character Large Object (CLOB), then you will need to create a custom converter that converts the CLOB to a String. For information about conversion, see Creating Custom ADF Faces Converters.

  4. In the Properties window, expand the Common section. If you have already bound your table to a model, the value attribute should be set. You can use this section to set the following table-specific attributes:

    • RowSelection: Set a value to make the rows selectable. Valid values are: none, single, and multiple, and multipleNoSelectAll.

      Note:

      Users can select all rows and all columns in a table by clicking the column header for the row header if the rowSelection attribute is set to multiple and that table also contains a row header. If you do not want users to be able to select all columns and rows, then set rowSelection to multipleNoSelectAll.

      For information about how to then programmatically perform some action on the selected rows, see What You May Need to Know About Performing an Action on Selected Rows in Tables.

    • ColumnSelection: Set a value to make the columns selectable. Valid values are: none, single, and multiple.

  5. Expand the Columns section. If you previously bound your table using the Create ADF Faces Table dialog, then these settings should be complete. You can use this section to change the binding for the table, to change the variable name used to access data for each row, and to change the display label and components used for each column.

    Tip:

    If you want to use a component other than those listed, select any component in the Properties window, and then manually change it:

    1. In the Structure window, right-click the component created by the dialog and choose Convert.

    2. Select the desired component from the list. You can then use the Properties window to configure the new component.

    Tip:

    If you want more than one component to be displayed in a column, add the other component manually and then wrap them both in a panelGroupLayout component. To do so:

    1. In the Structure window, right-click the first component and choose Insert before or Insert after. Select the component to insert.

    2. By default the components will be displayed vertically. To have multiple components displayed next to each other in one column, press the shift key and select both components in the Structure window. Right-click the selection and choose Surround With.

    3. Select panelGroupLayout.

  6. Expand the Appearance section. You use this section to set the appearance of the table, by setting the following table-specific attributes:

    • Width: Specify the width of the table. You can specify the width as either a number of pixels or as a percentage. The default setting is 300 pixels. If you configure the table to stretch columns (using the columnStretching attribute), you must set the width to percentages.

      Tip:

      If the table is a child to a component that stretches its children, then this width setting will be overridden and the table will automatically stretch to fit its container. For information about how components stretch, see Geometry Management for the Table, Tree, and Tree Table Components.

    • ColumnStretching: If the widths of the columns do not together fill the whole table, you can set this attribute to determine whether or not to stretch columns to fill up the space, and if so, which columns should stretch.

      Note:

      If the table is placed inside a component that can stretch its children, only the table will stretch automatically. You must manually configure column stretching if you want the columns to stretch to fill the table.

      Note:

      Columns configured to be row headers or configured to be frozen will not be stretched because doing so could easily leave the user unable to access the scrollable body of the table.

      Performance Tip:

      Column stretching is turned off by default. Turning on this feature may have a performance impact on the client rendering time for complex tables.

      You can set column stretching to one of the following values:

      • blank: If you want to have an empty blank column automatically inserted and have it stretch (so the row background colors will span the entire width of the table).

      • A specifically named column: Any column currently in the table can be selected to be the column to stretch.

      • last: If you want the last column to stretch to fill up any unused space inside of the window.

      • none: The default option where nothing will be stretched. Use this for optimal performance.

      • multiple: All columns that have a percentage value set for their width attribute will be stretched to that percent, once other columns have been rendered to their (nonstretched) width. The percentage values will be weighted with the total. For example, if you set the width attribute on three columns to 50%, each column will get 1/3 of the remaining space after all other columns have been rendered.

      Tip:

      While the widths of columns can change at runtime, those width values will not be retained once the user leaves the page unless you configure your application to use change persistence. For information about enabling and using change persistence, see Allowing User Customization on JSF Pages.

    • HorizontalGridVisible: Specify whether or not the horizontal grid lines are to be drawn.

    • VerticalGridVisible: Specify whether or not the vertical grid lines are to be drawn.

    • RowBandingInterval: Specify how many consecutive rows form a row group for the purposes of color banding. By default, this is set to 0, which displays all rows with the same background color. Set this to 1 if you want to alternate colors.

    • ColumnBandingInterval: Specify the interval between which the column banding occurs. This value controls the display of the column banding in the table. For example, columnBandingInterval=1 would display alternately banded columns in the table.

    • FilterVisible: You can add a filter to the table so that it displays only those rows that match the entered filter criteria. If you configure the table to allow filtering, you can set the filter to be case-insensitive or case-sensitive. For information, see Enabling Filtering in Tables.

    • ScrollPolicy: By default, on desktop devices, tables render a scroll bar that allows the user to scroll through all rows. On tablet devices, instead of a scroll bar, tables are rendered to display the table as paginated.

      Set the value to auto to keep this default behavior. Set the value to page to have the table always display the rows as sets of pages, with a navigation to those pages in the footer. Set the value to scroll for tablet devices to have the table always render a scroll bar and scroll with implicit high-water mark scrolling; this setting is particularly useful to address performance problems with virtualized scrolling of table data on tablets. You can specify the number of rows to cache to minimize database roundtrips when the user scrolls back by setting a value for the maxClientRows attribute.

      Set the value to scrollPrefetch for large tables when there are enough rows left to scroll to ensure smooth scrolling. Prefetching happens in parallel when a user is scrolling. When you set the value of the scrollPolicy attribute to scrollPrefetch, a table ensures the following:

      • When a table is rendered initially, it fetches more rows than that is enough to fill the table viewport depending on the configuration of the table. For example, if the fetchSize is 25 and the viewport is 12 rows high, there are 13 rows left to scroll, which is more than half of fetchSize and no additional row beyond the first block is fetched. However, if the fetchSize is 25 and the viewport is 13 rows high, there are only 12 rows left to scroll, which is less than half of fetchSize and therefore, an additional row will be fetched.

      • On subsequent scrolling of the table, the number of client rows left to scroll will be continually monitored and fetching of new data blocks is triggered when the number of rows left to scroll falls below the threshold. However, on tables with known row count, where virtualized scrollbar is supported, fetching will not be initiated until the user releases the mouse button from scrolling.

      Note:

      For desktop devices, in order to explicitly set a table to display as paginated (configured as the default for tablet devices), you must set the scrollPolicy attribute to page and the autoHeightRows attribute to 0. If these conditions are not met, the table will display with a scroll bar (whether it is a child to a stretched or a flowing component). For information about container components and tables, see Geometry Management for the Table, Tree, and Tree Table Components.

    • Text attributes: You can define text strings that will determine the text displayed when no rows can be displayed, as well as a table summary and description for accessibility purposes.

  7. Expand the Behavior section. You use this section to configure the behavior of the table by setting the following table-specific attributes:

    • ColumnResizing: Specify whether or not you want the end user to be able to resize a column's width at runtime. When set to disabled, the widths of the columns will be set once the page is rendered, and the user will not be able to change those widths.

      Tip:

      While the user can change the values of the column width at runtime when columnResizing is set to true, those width values will not be retained once the user leaves the page unless you configure your application to use change persistence. For information about enabling and using change persistence, see Allowing User Customization on JSF Pages.

    • DisableColumnReordering: By default, columns can be reordered at runtime using a menu option contained by default in the panelCollection component. You can change this so that users will not be able to change the order of columns. (The panelCollection component provides default menus and toolbar buttons for tables, trees, and tree tables. SeeDisplaying Table Menus, Toolbars, and Status Bars.)

      Note:

      While the user can change the order of columns, those values will not be retained once the user leaves the page unless you configure your application to allow user customization. See Allowing User Customization on JSF Pages.

    • FetchSize: Set the size of the block that should be returned with each data fetch. The default is 25.

      Tip:

      You should determine the value of the fetchSize attribute by taking the height of the table and dividing it by the height of each row to determine how many rows will be needed to fill the table. If the fetchSize attribute is set too low, it will require multiple trips to the server to fill the table. If it is set too high, the server will need to fetch more rows from the data source than needed, thereby increasing time and memory usage. On the client side, it will take longer to process those rows and attach them to the component. See Content Delivery. For slower database access set higher fetchSize in order to achieve continuous display and scrolling of data.

    • ContentDelivery: Specify when the data should be delivered. When the contentDelivery attribute is set to immediate, data is fetched at the same time the component is rendered. If the contentDelivery attribute is set to lazy, data will be fetched and delivered to the client during a subsequent request. If the attribute is set to whenAvailable (the default), the renderer checks if the data is available. If it is, the content is delivered immediately. If it is not, then lazy delivery is used. SeeContent Delivery.

    • AutoHeightRows: Specify the number of rows to initially display in the table. When the returned number of rows exceeds this value, a scrollbar is displayed. If you want your table to size to be the same as the fetchSize, set it to 0. If you want the table to stretch to fill its parent container that is configured to stretch children, set it to -1 (for information about stretching the table, see Geometry Management for the Table, Tree, and Tree Table Components.). Otherwise set it to a specific number that is lower than the current setting for fetchSize.

      Note:

      Note the following about setting the autoHeightRows attribute:

      • Specifying height on the inlineStyle attribute will have no effect and will be overridden by the value of AutoHeightRows.

      • Specifying a min-height or max-height on the inlineStyle attribute is not recommended and is incompatible with the autoHeightRows attribute.

      • When the component is placed in a layout-managing container, such as panelSplitter, it will be sized by the container (no auto-sizing will occur).

      Note:

      The default value for the autoHeightRows attribute is handled by the DEFAULT_DIMENSIONS web.xml parameter. If you always want table components to be stretched when the parent can stretch, and to be the size of the fetchSize attribute when it cannot, set the DEFAULT_DIMENSIONS parameter to auto, instead of setting the autoHeightRows attribute.

      When you set the DEFAULT_DIMENSIONS parameter to auto and place the table in a parent that does not stretch its children, and there is no override value for the autoHeightRows attribute, then the table will take its width from the AFStretchWidth style class, which by default, will stretch the width of the table to accommodate it's child column components.

      Set the autoHeightRows attribute when you want to override the global setting.

      By default, DEFAULT_DIMENSIONS is set so that the value of autoHeightRows is -1 (the table will not stretch). See Geometry Management for Layout and Table Components.

    • DisplayRow: Specify the row to be displayed in the table during the initial display. The possible values are first to display the first row at the top of the table, last to display the last row at the bottom of the table (users will need to scroll up to view preceding rows) and selected to display the first selected row in the table.

      Note:

      The total number of rows from the table model must be known in order for this attribute to work successfully.

    • EditingMode: Specify whether for any editable components, you want all the rows to be editable (editAll), you want the user to click a row to make it editable (clickToEdit), or you want the table to be rendered as read only (readOnly). For information, see Editing Data in Tables, Trees, and Tree Tables.

      Tip:

      If you choose clickToEdit, then only the active row can be edited. This row is determined by the activeRowKey attribute. By default, when the table is first rendered, the active row is the first visible row. When a user clicks another row, then that row becomes the active row. You can change this behavior by setting a different value for the activeRowKey attribute.

    • ContextMenuSelect: Specify whether or not the row is selected when you right-click to open a context menu. When set to true, the row is selected. For information about context menus, see Using Popup Dialogs, Menus, and Windows.

    • FilterModel: Use in conjunction with filterVisible. See Enabling Filtering in Tables.

    • Various listeners: Bind listeners to methods that will execute when the table invokes the corresponding event. See Handling Events.

  8. Expand the Advanced section and set the following table-specific attributes:

    • ActiveRowKey: If you choose clickToEdit, then only the active row can be edited. This row is determined by the activeRowKey attribute. By default, when the table is first rendered, the active row is the first visible row. When a user clicks another row, then that row becomes the active row. You can change this behavior by setting a different value for the activeRowKey attribute.

    • DisplayRowKey: Specify the row key to display in the table during initial display. This attribute should be set programmatically rather than declaratively because the value may not be strings. Specifying this attribute will override the displayRow attribute.

      Note:

      The total number of rows must be known from the table model in order for this attribute to work successfully.

  9. Expand the Other section and set the following:

    • BlockRowNavigationOnError: Specify if you want users to be able to navigate away from a row that contains a validation error. When set to always, whenever a validation error occurs for a row, the user will always be blocked from navigating to a different row. When set to never, the user will never be blocked from navigating to a different row. When set to auto (the default), the framework will determine if the user can navigate.

      For example, there may be cases when the table shares its values with another component on the page. You might have a table that allows the user to view a number of different records. When a specific record is selected, its information is displayed in a form. If the user changes some data in the form that causes an error, you do not want the user to then be able to scroll away from that record using the table. So for this example, you might set BlockRowNavigationOnError to always.

    • FreezeDirection: If you want columns to be able to be frozen, specify whether they should be frozen from the start of the table (the left side in a LTR locale) or the end of the table (the right side in a LTR locale). You must configure the column to start to the freeze using that column's frozen attribute.

      For example, say you want the first three columns to be frozen. On the table, you would set freezeDirection to start, and on the third column, you would set frozen to true.

      If you want the last four columns to be frozen, you would set freezeDirection to end, and on the fourth from last column, you would set frozen to true

    • SelectionEventDelay: Set to true if you expect users to navigate through the table using the up and down arrow keys.

      Users can navigate through the table using a mouse and the scrollbar, or using the up and down arrow keys. By default, a selection event is immediately fired when the user clicks a row. If the user is navigating through the rows using the arrow keys, this means that a selection event will be fired for each row, as the user navigates.

      If you expect users to navigate through the table using the keys, you can set the selectionEventDelay attribute to true, so that there is a 300 millisecond delay before the selection event is fired. If the user navigates to another row within the 300 milliseconds, the selection event is canceled.

  10. In the Structure window, select a column. In the Properties window, expand the Common section, and set the following column-specific attributes:

    • HeaderText: Specify text to be displayed in the header of the column. This is a convenience that generates output equivalent to adding a header facet containing an outputText component. If you want to use a component other than outputText, you should use the column's header facet instead (See Step 16). When the header facet is added, any value for the headerText attribute will not be rendered in a column header.

    • Align: Specify the alignment for this column. start, end, and center are used for left-justified, right-justified, and center-justified respectively in left-to-right display. The values left or right can be used when left-justified or right-justified cells are needed, irrespective of the left-to-right or right-to-left display. The default value is null, which implies that it is skin-dependent and may vary for the row header column versus the data in the column. For information about skins, see Customizing the Appearance Using Styles and Skins.

    • Sortable: Specify whether or not the column can be sorted. A column that can be sorted has a header that when clicked, sorts the table by that column's property. Note that in order for a column to be sortable, the sortable attribute must be set to true and the underlying model must support sorting by this column's property. See What You May Need to Know About Programmatically Enabling Sorting for Table Columns.

      Note:

      When column selection is enabled, clicking on a column header selects the column instead of sorting the column. In this case, columns can be sorted by clicking the ascending/descending sort indicator.

    • SortStrength: Specify the level of difference to be considered significant when sorting. Choose from one of the following (these values are the same as the values for the Java Collator object):

      • Primary: The sorting considers only the letter itself. Case and any accents are ignored: abc, ÁBC, ábc, and ABC will be sorted as abc, ÁBC, ábc,ABC (the order in which they appear). Use this for case-insensitive sorting.

      • Secondary: The sorting considers the letter and then any accent. Case is ignored: abc, ÁBC, ábc, and ABC will be sorted as abc, ABC, ÁBC, ábc. In locales that do not have accents, this will result in a case-insensitive search.

      • Tertiary: The sorting will consider the letter, then the accent, and then the case: abc, ÁBC, ábc, and ABC will be sorted as abc, ABC, ábc, ÁBC. In locales that do not have accents, this will result in a case-sensitive search.

      • Identical: The letters, accents, cases, and any other differences (such as words with punctuation) will be considered: abc, ab-c, ÁBC, ábc, and ABC will be sorted as abc, ABC, ábc, ÁBC, ab-c. This will result in a case-sensitive search, and is the default.

    • Filterable: Specify whether or not the column can be filtered. A column that can be filtered has a filter field on the top of the column header. Note that in order for a column to be filterable, this attribute must be set to true and the filterModel attribute must be set on the table. Only leaf columns can be filtered and the filter component is displayed only if the column header is present. This column's sortProperty attribute must be used as a key for the filterProperty attribute in the filterModel class.

      Note:

      For a column with filtering turned on (filterable=true), you can specify the input component to be used as the filter criteria input field. To do so, add a filter facet to the column and add the input component. See Enabling Filtering in Tables.

  11. Expand the Appearance section. Use this section to set the appearance of the column, using the following column-specific attributes:

    • DisplayIndex: Specify the display order index of the column. Columns can be rearranged and they are displayed in the table based on the displayIndex attribute. Columns without a displayIndex attribute value are displayed at the end, in the order in which they appear in the data source. The displayIndex attribute is honored only for top-level columns, because it is not possible to rearrange a child column outside of the parent column.

    • Width: Specify the width of the column. If the table uses column stretching, then you must enter a percentage for the width.

      In column stretching, column width percentages are treated as weights. For example, if all columns are given 50% widths, and there are more than three columns, each column will receive an equal amount of space, while still respecting the value set for the minWidth attribute.

      Because the width as a percentage is a weight rather than an actual percentage of space, if column stretching is turned on in the table, and only one column is listed as being stretched by having a percentage width, that column will use up all remaining space in the table not specified by pixel widths in the rest of the columns.

    • MinimumWidth: Specify the minimum number of pixels for the column width. When a user attempts to resize the column, this minimum width will be enforced. Also, when a column is flexible, it will never be stretched to be a size smaller than this minimum width. If a pixel width is defined and if the minimum width is larger, the minimum width will become the smaller of the two values. By default, the minimum width is 10 pixels.

    • ShowRequired: Specify whether or not an asterisk should be displayed in the column header if data is required for the corresponding attribute.

    • HeaderNoWrap and NoWrap: Specify whether or not you want content to wrap in the header and in the column.

    • RowHeader: Set to true if you want this column to be a row header for the table.

      Performance Tip:

      Use of row headers increases the complexity of tables and can have a negative performance impact.

  12. Expand the Behavior section. Use this section to configure the behavior of the columns, using the following column-specific attributes:

    • SortProperty: Specify the property that is to be displayed by this column. This is the property that the framework might use to sort the column's data.

    • Frozen: Specify whether the column is frozen; that is it can't be scrolled off the page. In the table, columns up to the frozen column are locked with the header, and not scrolled with the rest of the columns. The frozen attribute is honored only on the top-level column, because it is not possible to freeze a child column by itself without its parent being frozen.

      Note:

      By default, columns are frozen from this column to the left. That is, this column and any column to the left of it, will not scroll. You can change this by setting the freezeDirection attribute on the table component to end. By default, it is set to start.

      Performance Tip:

      Use of frozen columns increases the complexity of tables and can have a negative performance impact.

    • Selected: When set to true, the column will be selected on initial rendering.

  13. If you want this column to span over subsequent columns, expand the Other section and set ColSpan. You can set it to the number of columns you want it to span, or you can set it to ALL to span to the end of the table. If you don't want all cells in the column to span, you can use an EL expression that resolves to a specific cell or cells.

    The following example shows how you might set colSpan in a tree table component where you want only the parent node to span across all columns.

    <af:column id="c1" sortable="true" sortProperty="Dname" 
               colSpan="#{testBean.container ? 'ALL' : '1'}"
               headerText="DepartmentName">
      <af:outputText value="#{node.Dname}" id="ot2"/>
    </af:column>
    

    The following example shows the corresponding managed bean code.

    public class TestBean 
    {
      public boolean isContainer() 
      {
        return _treeTable.isContainer();
      }
    }
    
  14. To add a column to an existing table, in the Structure window, right-click the table and choose Insert Inside Table > Column. To create column groups, drag a column component and drop it as a child to the component that will be the header. Continue to add columns to create the group. Set the headerText attribute on the parent column.

  15. To add facets to the table, right-click the table and choose Facets - Table and choose the type of facet you want to add. You can then add a component directly to the facet.

    Tip:

    Because facets on a JSP or JSPX accept one child component only, if you want to add more than one child component, you must wrap the child components inside a container, such as a panelGroupLayout or group component. Facets on a Facelets page can accept more than one component.

  16. To add facets to a column, right-click the column and choose Facets - Column, and choose the type of facet you want to add. You can then add a component directly to the facet.

    Tip:

    Because facets on a JSP or JSPX accept one child component only, if you want to add more than one child component, you must wrap the child components inside a container, such as a panelGroupLayout or group component. Facets on a Facelets page can accept more than one component.

  17. Add components as children to the columns to display your data.

    The component's value should be bound to the variable value set on the table's var attribute and the attribute to be displayed. For example, the table in the File Explorer application uses file as the value for the var attribute, and the first column displays the name of the file for each row. Therefore, the value of the output component used to display the directory name is #{file.name}.

    Tip:

    If an input component is the direct child of a column, be sure its width is set to a width that is appropriate for the width of the column. If the width is set too large for its parent column, the browser may extend its text input cursor too wide and cover adjacent columns. For example, if an inputText component has its size set to 80 pixels and its parent column size is set to 20 pixels, the table may have an input cursor that covers the clickable areas of it neighbor columns.

    To allow the input component to be automatically sized when it is not the direct child of a column, set contentStyle="width:auto".

What Happens When You Add a Table to a Page

When you use JDeveloper to add a table onto a page, JDeveloper creates a table with a column for each attribute. If you bind the table to a model, the columns will reflect the attributes in the model. If you are not yet binding to model, JDeveloper will create the columns using the default values. You can change the default values (add/delete columns, change column headings, and so on) during in the table creation dialog or later using the Properties window.

The following example shows abbreviated page code for the table in the File Explorer application.

<af:table id="folderTable" var="file"
          value="#{explorer.contentViewManager.
                                    tableContentView.contentModel}"
           binding="#{explorer.contentViewManager.
                                    tableContentView.contentTable}"
           emptyText="#{explorerBundle['global.no_row']}"
           rowselection="multiple"
           contextMenuId=":context1" contentDelivery="immediate"
           columnStretching="last"
           selectionListener="#{explorer.contentViewManager.
                              tableContentView.tableFileItem}"
           summary="table data">
  <af:column width="180" sortable="true" sortStrength="identical" 
             sortProperty="name" 
             headerText="" align="start">
    <f:facet name="header">
      <af:outputText value="#{explorerBundle['contents.name']}"/>
    </f:facet>
    <af:panelGroupLayout>
      <af:image source="#{file.icon}"
                inlineStyle="margin-right:3px; vertical-align:middle;"
                shortDesc="file icon"/>
      <af:outputText value="#{file.name}" noWrap="true"/>
    </af:panelGroupLayout>
  </af:column>
  <af:column width="70" sortable="true" sortStrength="identical"
             sortProperty="property.size">
    <f:facet name="header">
      <af:outputText value="#{explorerBundle['contents.size']}"/>
    </f:facet>
    <af:outputText value="#{file.property.size}" noWrap="true"/>
  </af:column>
...
  <af:column width="100">
    <f:facet name="header">
      <af:outputText value="#{explorerBundle['global.properties']}"/>
    </f:facet>
    <af:link text="#{explorerBundle['global.properties']}"
                    partialSubmit="true"
                    action="#{explorer.launchProperties}"
                    returnListener="#{explorer.returnFromProperties}"
                    windowWidth="300" windowHeight="300"
                    useWindow="true">
    </af:link>
  </af:column>
</af:table>

What Happens at Runtime: Data Delivery

When a page is requested that contains a table, and the content delivery is set to lazy, the page initially goes through the standard lifecycle. However, instead of fetching the data during that request, a special separate PPR request is run. Because the page has just rendered, only the Render Response phase executes, and the corresponding data is fetched and displayed. If the user's actions cause a subsequent data fetch (for example scrolling in a table), another PPR request is executed. Figure 12-22 shows a page containing a table during the second PPR request. A message is displayed to let the user know that the data is being fetched.

Figure 12-22 Table Fetches Data in a Second PPR Request

Description of Figure 12-22 follows
Description of "Figure 12-22 Table Fetches Data in a Second PPR Request"

When the user clicks a sortable column header, the table component generates a SortEvent event. This event has a getSortCriteria property, which returns the criteria by which the table must be sorted, along with the sort strength. The table responds to this event by calling the setSortCriteria() method on the underlying CollectionModel instance, and calls any registered SortListener instances.

What You May Need to Know About Programmatically Enabling Sorting for Table Columns

Sorting can be enabled for a table column only if the underlying model supports sorting. If the model is a CollectionModel instance, it must implement the following methods:

  • public boolean isSortable(String propertyName)

  • public List getSortCriteria()

  • public void setSortCriteria(List criteria)

The criteria in the second and third methods is a list where each item in the list is an instance of org.apache.myfaces.trinidad.model.SortCriterion, which supports sort strength.

See the MyFaces Trinidad website at http://myfaces.apache.org/trinidad/index.html.

If the model is not a CollectionModel instance, the table component wraps that model into an org.apache.myfaces.trinidad.model.SortableModel instance and converts the model to a CollectionModel instance that is sortable (SortableModel is a concrete class that extends CollectionModel and implements sorting functionality). In this case, the table will examine the actual data to determine which properties are sortable. Any column that has data that implements java.lang.Comparable will be sortable. This automatic support for sorting by the table is not as efficient as sorting directly into a CollectionModel instance but is sufficient for small data sets. Note that tables with a converted model allow sorting for only one column and therefore multi-column table sorting (normally done by supplying multiple sort criteria) is not supported on the converted model.

Note:

When the underlying table model is not a CollectionModel instance and multi-column sorting is desired, consider using the table inside a panelCollection component. The panel user interface allows the user to sort using multiple sort criteria even though automatic sorting provided by the table with a converted model does not support it. For details about the panelCollection component, see How to Add a panelCollection with a Table, Tree, or Tree Table.

What You May Need to Know About Performing an Action on Selected Rows in Tables

A collection-based component can allow users to select one or more rows and perform some actions on those rows (the carousel component does not support multiple selection).

When the selection state of a component changes, the component triggers selection events. A selectionEvent event reports which rows were just deselected and which rows were just selected.

To listen for selection events on a component, you can register a listener on the component either using the selectionListener attribute or by adding a listener to the component using the addselectionListener() method. The listener can then access the selected rows and perform some actions on them.

The current selection, that is the selected row or rows, are the RowKeySet object, which you obtain by calling the getSelectedRowKeys() method for the component. To change a selection programmatically, you can do either of the following:

  • Add rowKey objects to, or remove rowKey objects from, the RowKeySet object.

  • Make a particular row current by calling the setRowIndex() or the setRowKey() method on the component. You can then either add that row to the selection, or remove it from the selection, by calling the add() or remove() method on the RowKeySet object.

The following example shows a portion of a table in which a user can select some rows then click the Delete button to delete those rows. Note that the actions listener is bound to the performDelete method on the mybean managed bean.

<af:table binding="#{mybean.table}" rowselection="multiple" ...>
  ...
</af:table>
<af:button text="Delete" actionListener="#{mybean.performDelete}"/>

The following example shows an actions method, performDelete, which 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.getSelectedRowKeys().iterator();
  Object oldKey = table.getRowKey();
  try
  {
    while(selection.hasNext())
    {
      Object rowKey = selection.next();
      table.setRowKey(rowKey);
      MyRowImpl row = (MyRowImpl) table.getRowData();
      //custom method exposed on an implementation of Row interface.
      row.markForDeletion();
    }
  }
  finally
  {
    // restore the old key:
    table.setRowKey(oldKey);
  }
}

Note:

When using setRowKey and setRowIndex on table/tree/treeTable to change the current record for operation, you must restore the old current record after the operation. Otherwise, failure to restore the old currency can cause application errors.

What You May Need to Know About Dynamically Determining Values for Selection Components in Tables

There may be a case when you want to use a selectOne component in a table, but you need each row to display different choices in a component. Therefore, you need to dynamically determine the list of items at runtime.

While you may think you should use a forEach component to stamp out the individual items, this will not work because forEach does not work with the CollectionModel instance. It also cannot be bound to EL expressions that use component-managed EL variables, as those used in the table. The forEach component performs its functions in the JSF tag execution step while the table performs in the following component encoding step. Therefore, the forEach component will execute before the table is ready and will not perform its iteration function.

In the case of a selectOne component, the direct child must be the items component. While you could bind the items component directly to the row variable (for example, <f:items value="#{row.Items}"/>, doing so would not allow any changes to the underlying model.

Instead, you should create a managed bean that creates a list of items, as shown in the following example.

public List<SelectItem> getItems()
{
   // Grab the list of items
   FacesContext context = FacesContext.getCurrentInstance();
   Object rowItemObj =  context.getApplication().evaluateExpressionGet(
      context, "#{row.items}", Object.class);
   if (rowItemObj == null)
     return null;
    // Convert the model objects into items 
   List<SomeModelObject> list =  (List<SomeModelObject>) rowItemObj;
   List<SelectItem> items = new ArrayList<SelectItem>(list.size());
   for (SomeModelObject entry : list)
   {
     items.add(new SelectItem(entry.getValue(), entry.getLabel());public
    }
    // Return the items
    return items;
}

You can then access the list from the one component on the page:

<af:table var="row">
  <af:column>
    <af:selectOneChoice value="#{row.myValue}">
      <f:Items value="#{page_backing.Items}"/>
    </af:selectOneChoice>
  </af:column>
</af:table>

What You May Need to Know About Read Only Tables

A table can be set as read-only by setting the editingMode attribute to readOnly value. If the editingMode attribute is set to clickToEdit type, then the table will result in a regular clickToEdit behavior.

A table can be rendered as editable, read-only, or edit-upon-clicking a row or a node type by setting an appropriate value on the editingMode attribute. When the editingMode attribute is set to readyOnly value, all the components of that table will be rendered as read-only, including input components. If editingMode is set to clickToEdit value, then that table will result in a regular clickToEdit behavior.

Setting the web.xml parameter oracle.adf.view.rich.table.clickToEdit.initialRender.readOnly will force all clickToEdit type tables in an application to render as read-only only when the tables are initially loaded. All tables using other editingMode settings will be unaffected. See Rendering Tables Initially as Read Only.

The var status of the table is updated with a new variable readOnly (varStatus.readOnly). This will provide information about the current status of the row if it is read-only or not. Applications can use this variable along with other conditional operators to decide which component to render. Following is example code using varStatus.readOnly to render an input text for an editable row and output text for a read-only row.

  • You can add varStatus attribute in your table as follows:
    <af:table value="#{bindings.EmpView1.collectionModel}" var="row"
              rows="#{bindings.EmpView1.rangeSize}"
              emptyText="#{bindings.EmpView1.viewable ? 'No data to display.' : 'Access Denied.'}"
              fetchSize="#{bindings.EmpView1.rangeSize}"
              rowBandingInterval="0" id="t1" inlineStyle="width:1000px;" editingMode="clickToEdit" 
    varStatus="vars" binding="#{backingBeanScope.Backing.t1}"
              partialTriggers="::cb4 ::cb5 ::cb6 ::cb7 deptno1Id" columnSelection="single">
  • You can use varStatus attribute in your column definition as follows:
    <af:column headerText="switch" id="c100" width="130px">
     <af:inputText value="#{row.bindings.Hiredate.inputValue}"
              required="#{bindings.EmpView1.hints.Hiredate.mandatory}"
              columns="#{bindings.EmpView1.hints.Hiredate.displayWidth}"
              maximumLength="#{bindings.EmpView1.hints.Hiredate.precision}"
              shortDesc="#{bindings.EmpView1.hints.Hiredate.tooltip}"
              id="it2" rendered="#{!vars.readOnly}">
      <af:validator binding="#{row.bindings.Hiredate.validator}"/>
      <af:convertDateTime pattern="#{bindings.EmpView1.hints.Hiredate.format}"/>
     </af:inputText>
     <af:outputText value="outputtext #{row.Hiredate}" id="ot2" rendered="#{vars.readOnly}">
      <af:convertDateTime pattern="#{bindings.EmpView1.hints.Hiredate.format}"/>
     </af:outputText>
    </af:column>

Adding Hidden Capabilities to a Table

While displaying the content in an ADF table built with collection-based components you can hide or display some content using detailStamp facet. The content appears with a toggle icon, when user clicks on it the hidden text is displayed in a popup window.

You can use the detailStamp facet in a table to include data that can be displayed or hidden. When you add a component to this facet, the table displays an additional column with a toggle icon. When the user clicks the icon, the component added to the facet is shown. When the user clicks on the toggle icon again, the component is hidden. Figure 12-23 shows the additional column that is displayed when content is added to the detailStamp facet.

Figure 12-23 Table with Unexpanded DetailStamp Facet

This image is described in the surrounding text.

Figure 12-24 shows the same table, but with the detailStamp facet expanded for the first row.

Figure 12-24 Expanded detailStamp Facet

This image is described in the surrounding text.

You can use an EL expression for the rendered attribute on the facet to determine whether or not to display the toggle icon and show details. For example, say on a shopping cart page you want to use the detailStamp facet to display gift wrapping information. However, not all order items will have gift wrapping information, so you only want the toggle icon to display if the order item has the information to display. You could create a method on managed bean that determines if there is information to display, and then bind the rendered attribute to that method. Figure 12-25 shows the same table but with icons displayed only for the rows that have information to display.

Figure 12-25 Conditional detailStamp Facet

This image is described in the surrounding text.

Note:

If you set the table to allow columns to freeze, the freeze will not work when you display the detailStamp facet. That is, a user cannot freeze a column while the details are being displayed.

How to Use the detailStamp Facet

To use the detailStamp facet, you insert a component that is bound to the data to be displayed or hidden into the facet.

Before you begin:

It may be helpful to have an understanding of how the attributes can affect functionality. See Adding Hidden Capabilities to a Table.

You may also find it helpful to understand functionality that can be added using other ADF Faces features. See Additional Functionality for Collection-Based Components.

To use the detailStamp facet:

  1. In the Components window, drag the components you want to appear in the facet to the detailStamp facet in the Structure window, as shown in Figure 12-26.

    Figure 12-26 detailStamp Facet in the Structure Window

    Description of Figure 12-26 follows
    Description of "Figure 12-26 detailStamp Facet in the Structure Window"

    Note:

    Because facets on a JSP or JSPX accept one child component only, if you want to add more than one child component, you must wrap the child components inside a container, such as a panelGroupLayout or group component. Facets on a Facelets page can accept more than one component.

    Tip:

    If the facet does not appear in the Structure window, right-click the table and choose Facets - Table > Detail Stamp.

  2. If the attribute to be displayed is specific to a current record, replace the JSF code (which simply binds the component to the attribute), so that it uses the table's variable to display the data for the current record.

    The following example shows abbreviated code used to display the detailStamp facet shown in Figure 12-24, which shows details about the selected row.

    <af:table rowSelection="multiple" var="test1"
              value="#{tableTestData}"
      <f:facet name="detailStamp">
        <af:panelFormLayout rows="4" labelWidth="33%" fieldWidth="67%"
                            inlineStyle="width:400px">
        <af:inputText label="Name" value="#{test1.name}"/>
          <af:group>
            <af:inputText label="Size" value="#{test1.size}"/>
            <af:inputText label="Date Modified" value="#{test1.inputDate}"/>
            <af:inputText label="Created by"/>
          </af:group>
        </af:panelFormLayout>
      </f:facet>
    </af:table>
    
  3. If you want the detailStamp facet to display its icon and components conditionally, set the rendered attribute on the facet to a method on a managed bean that will determine if the facet should be rendered.

Note:

If your application uses the Fusion technology stack, then you can drag attributes from a data control and drop them into the detailStamp facet. You don't need to modify the code.

What Happens at Runtime: The rowDisclosureEvent

When the user hides or shows the details of a row, the table generates a rowDisclosureEvent event. The event tells the table to toggle the details (that is, either expand or collapse).

The rowDisclosureEvent event has an associated listener. You can bind the rowDisclosureListener attribute on the table to a method on a managed bean. This method will then be invoked in response to the rowDisclosureEvent event to execute any needed post-processing.

Enabling Filtering in Tables

An ADF table built with collection-based components can filter data in the table if the filterModel attribute object of the table is bound to an instance of the FilterableQueryDescriptor class.

You can add a filter to a table that can be used so that the table displays only rows whose values match the filter. When enabled and set to visible, a search criteria input field displays above each searchable column.

For example, the table in Figure 12-27 has been filtered to display only rows in which the Location value is 1700.

Filtered table searches are based on Query-by-Example and use the QBE text or date input field formats. The input validators are turned off to allow for entering characters for operators such as > and < to modify the search criteria. For example, you can enter >1500 as the search criteria for a number column. Wildcard characters may also be supported. Searches can be either case-sensitive or case-insensitive. If a column does not support QBE, the search criteria input field will not render for that column.

The filtering feature uses a model for filtering data into the table. The table's filterModel attribute object must be bound to an instance of the FilterableQueryDescriptor class.

Note:

If your application uses the Fusion technology stack, then you can use data controls to create tables and filtering will be created for you. See Creating ADF Databound Tables in Developing Web User Interfaces with Oracle ADF Faces

In the following example, the table filterVisible attribute is set to true to enable the filter input fields. For each column to be filtered, you must set the sortProperty attribute to the associated column in the filterModel instance and the filterable attribute set to true.

<af:table value="#{myBean.products}" var="row"
               ...
          filterVisible="true"
               ...
          rowselection="single">
               ...
  <af:column sortProperty="ProductID" filterable="true" sortable="true"
    <af:outputText value="#{row.ProductID}">
               ...
  </af:column>
  <af:column sortProperty="Name" filterable="true" sortable="true"
    <af:outputText value="#{row.Name}"/>
               ...
  </af:column>
  <af:column sortProperty="warehouse" filterable="true" sortable="true"
    <af:outputText value="#{row.warehouse}"/>
               ...
  </af:column>
</af:table>

How to Add Filtering to a Table

To add filtering to a table, first create a class that can provide the filtering functionality. You then bind the table to that class, and configure the table and columns to use filtering. The table that will use filtering must either have a value for its headerText attribute, or it must contain a component in the header facet of the column that is to be filtered. This allows the filter component to be displayed. Additionally, the column must be configured to be sortable, because the filterModel class uses the sortProperty attribute.

Before you begin:

It may be helpful to have an understanding of how the attributes can affect functionality. See Enabling Filtering in Tables.

You may also find it helpful to understand functionality that can be added using other ADF Faces features. See Additional Functionality for Collection-Based Components.

To add filtering to a table:

  1. Create a Java class that is a subclass of the FilterableQueryDescriptor class.

    The ConjunctionCriterion object returned from the getFilterConjunctionCriterion method must not be null. For information about this class, see the ADF Faces Javadoc.

  2. Create a table, as described in Displaying Data in Tables.

  3. Select the table in the Structure window and set the following attributes in the Properties window:

    • FilterVisible: Set to true to display the filter criteria input field above searchable column.

    • FilterModel: Bind to an instance of the FilterableQueryDescriptor class created in Step 1.

    Tip:

    If you want to use a component other than an inputText component for your filter (for example, an inputDate component), then instead of setting filterVisible to true, you can add the needed component to the filter facet. To do so:

    1. In the Structure window, right-click the column to be filtered and choose Insert inside af:column > JSF Core > Filter facet.

    2. From the Components window, drag and drop a component into the facet.

    3. Set the value of the component to the corresponding attribute within the FilterableQueryDescriptor class created in Step 1. Note that the value must take into account the variable used for the row, for example:

      #{af:inputDate label="Select Date" id="name"
                           value="row.filterCriteria.date"}
  4. In the Structure window, select a column in the table and in the Properties window, and set the following for each column in the table:

    • Filterable: Set to true.

    • FilterFeatures: Set to caseSensitive or caseInsensitive. If not specified, the case sensitivity is determined by the model.

Displaying Data in Trees

Any hierarchical data can be displayed using ADF tree component.

The ADF Faces tree component displays hierarchical data, such as organization charts or hierarchical directory structures. In data of these types, there may be a series of top-level nodes, and each element in the structure may expand to contain other elements. For example, in an organization chart, any number of employees in the hierarchy may have any number of direct reports. The tree component can be used to show that hierarchy, where the direct reports appear as children to the node for the employee.

The tree component supports multiple root elements. It displays the data in a form that represents the structure, with each element indented to the appropriate level to indicate its level in the hierarchy, and connected to its parent. Users can expand and collapse portions of the hierarchy. Figure 12-28 shows a tree used to display directories in the File Explorer application.

Figure 12-28 Tree Component in the File Explorer Application

Description of Figure 12-28 follows
Description of "Figure 12-28 Tree Component in the File Explorer Application"

The ADF Faces tree component uses a model to access the data in the underlying hierarchy. The specific model class is oracle.adf.view.rich.model.TreeModel, which extends CollectionModel, described in Displaying Data in Tables.

You must create your own tree model to support your tree. The tree model is a collection of rows. It has an isContainer() method that returns true if the current row contains child rows. To access the children of the current row, you call the enterContainer() method. Calling this method results in the TreeModel instance changing to become a collection of the child rows. To revert back up to the parent collection, you call the exitContainer() method.

You may find the org.apache.myfaces.trinidad.model.ChildPropertyTreeModel class useful when constructing a TreeModel class, as shown in the following example.

List<TreeNode> root = new ArrayList<TreeNode>();
for(int i = 0; i < firstLevelSize; i++)
{
  List<TreeNode> level1 = new ArrayList<TreeNode>();
  for(int j = 0; j < i; j++)
  {
    List<TreeNode> level2 = new ArrayList<TreeNode>();
    for(int k=0; k<j; k++)
    {
      TreeNode z = new TreeNode(null, _nodeVal(i,j,k));  
      level2.add(z);
    }
    TreeNode c = new TreeNode(level2, _nodeVal(i,j));
    level1.add(c);
  }
  TreeNode n = new TreeNode(level1, _nodeVal(i));
  root.add(n);
}
ChildPropertyTreeModel model = new ChildPropertyTreeModel(root, "children");
private String _nodeVal(Integer... args)
{
  StringBuilder s = new StringBuilder();
  for(Integer i : args)
    s.append(i);
  return s.toString();
}

Note:

If your application uses the Fusion technology stack, then you can use data controls to create trees and the model will be created for you. See Displaying Master-Detail Data in Developing Web User Interfaces with Oracle ADF Faces

You can manipulate the tree similar to the way you can manipulate a table. You can do the following:

  • To make a node current, call the setRowIndex() method on the tree with the appropriate index into the list. Alternatively, call the setRowKey() method with the appropriate rowKey object.

  • To access a particular node, first make that node current, and then call the getRowData() method on the tree.

  • To access rows for expanded or collapsed nodes, call getAddedSet and getRemovedSet methods on the RowDisclosureEvent. See What You May Need to Know About Programmatically Expanding and Collapsing Nodes.

  • To manipulate the node's child collection, call the enterContainer() method before calling the setRowIndex() and setRowKey() methods. Then call the exitContainer() method to return to the parent node.

  • To point to a rowKey for a node inside the tree (at any level) use the focusRowKey attribute. The focusRowKey attribute is set when the user right-clicks on a node and selects the Show as top (or the Show as top toolbar button in the panelCollection component).

    When the focusRowKey attribute is set, the tree renders the node pointed to by the focusRowKey attribute as the root node in the Tree and displays a Hierarchical Selector icon next to the root node. Clicking the Hierarchical Selector icon displays a Hierarchical Selector dialog which shows the path to the focusRowKey object from the root node of the tree. How this displays depends on the components placed in the pathStamp facet.

Note:

You cannot use JavaScript to dynamically size a tree. The height of a tree is set the first time is rendered and cannot be changed using JavaScript APIs.

As with tables, trees use stamping to display content for the individual nodes. Trees contain a nodeStamp facet, which is a holder for the component used to display the data for each node. Each node is rendered (stamped) once, repeatedly for all nodes. As each node is stamped, the data for the current node is copied into a property that can be addressed using an EL expression. Specify the name to use for this property using the var property on the tree. Once the tree has completed rendering, this property is removed or reverted back to its previous value.

Because of this stamping behavior, only certain types of components are supported as children inside an ADF Faces tree. All components that have no behavior are supported, as are most components that implement the ValueHolder or ActionSource interfaces.

In the following example, the data for each element is referenced using the variable node, which identifies the data to be displayed in the tree. The nodeStamp facet displays the data for each element by getting further properties from the node variable:

<af:tree var="node">
  <f:facet name="nodeStamp">
    <af:outputText value="#{node.firstname}"/>
  </f:facet>
</af:tree>

Trees also contain a pathStamp facet. This facet determines how the content of the Hierarchical Selector dialog is rendered, just like the nodeStamp facet determines how the content of the tree is rendered. The component inside the pathStamp facet can be a combination of simple outputText, image, and outputFormatted tags and cannot not be any input component (that is, any EditableValueHolder component) because no user input is allowed in the Hierarchical Selector popup. If this facet is not provided, then the Hierarchical Selector icon is not rendered.

For example, including an image and an outputText component in the pathStamp facet causes the tree to render an image and an outputText component for each node level in the Hierarchical Selector dialog. Use the same EL expression to access the value. For example, if you want to show the first name for each node in the path in an outputText component, the EL expression would be <af:outputText value="#{node.firstname}"/>.

Tip:

The pathStamp facet is also used to determine how default toolbar buttons provided by the panelCollection component will behave. If you want to use the buttons, add a component bound to a node value. For information about using the panelCollection component, see Displaying Table Menus, Toolbars, and Status Bars.

How to Display Data in Trees

To create a tree, you add a tree component to your page and configure the display and behavior properties.

Before you begin:

It may be helpful to have an understanding of how the attributes can affect functionality. See Displaying Data in Trees.

You may also find it helpful to understand functionality that can be added using other ADF Faces features. See Additional Functionality for Collection-Based Components.

To add a tree to a page:

  1. Create a Java class that extends the org.apache.myfaces.trinidad.model.TreeModel class.
  2. In the Components window, from the Data Views panel, drag and drop a Tree to open the Insert Tree dialog.
  3. Configure the tree as needed. For help with the dialog, click Help or press F1.
  4. In the Properties window, expand the Data section and set the following attributes:
    • Value: Specify an EL expression for the object to which you want the tree to be bound. This must be an instance of org.apache.myfaces.trinidad.model.TreeModel as created in Step 1.

    • Var: Specify a variable name to represent each node.

    • VarStatus: Optionally enter a variable that can be used to determine the state of the component. During the Render Response phase, the tree iterates over the model rows and renders each node. For any given node, the varStatus attribute provides the following information:

      • model: A reference to the CollectionModel instance

      • index: The current row index

      • rowKey: The unique key for the current node

  5. Expand the Appearance section and set the following attributes:
    • DisplayRow: Specify the node to display in the tree during the initial display. The possible values are first to display the first node, last to display the last node, and selected to display the first selected node in the tree. The default is first.

    • DisplayRowKey: Specify the row key to display in the tree during the initial display. This attribute should be set only programmatically. Specifying this attribute will override the displayRow attribute.

    • Summary: Optionally enter a summary of the data displayed by the tree.

  6. Expand the Behavior section and set the following attributes:
    • InitiallyExpanded: Set to true if you want all nodes expanded when the component first renders.

    • EditingMode: Specify whether for any editable components used to display data in the tree, you want all the nodes to be editable (editAll), you want the user to click a node to make it editable (clickToEdit), or you want the tree to be rendered as read only (readOnly). See Editing Data in Tables, Trees, and Tree Tables.

    • ContextMenuSelect: Determines whether or not the node is selected when you right-click to open a context menu. When set to true, the node is selected. For information about context menus, see Using Popup Dialogs, Menus, and Windows.

    • RowSelection: Set a value to make the nodes selectable. Valid values are: none, single, or multiple. For information about how to then programmatically perform some action on the selected nodes, see What You May Need to Know About Programmatically Selecting Nodes.

    • ContentDelivery: Specify when the data should be delivered. When the contentDelivery attribute is set to immediate, data is fetched at the same time the component is rendered. If the contentDelivery attribute is set to lazy, data will be fetched and delivered to the client during a subsequent request. If the attribute is set to whenAvailable (the default), the renderer checks if the data is available. If it is, the content is delivered immediately. If it is not, then lazy delivery is used. See Content Delivery.

    • FetchSize: Specify the number of rows in the data fetch block. See Content Delivery.

    • AutoHeightRows: Set to the maximum number of nodes to display before a scroll bar is displayed. The default value is -1 (no automatic sizing for any number of number). You can set the value to 0 to have the value be the same as the fetchSize value.

      Note:

      Note the following about setting the autoHeightRows attribute:

      • Specifying height on the inlineStyle attribute will have no effect and will be overridden by the value of AutoHeightRows.

      • Specifying a min-height or max-height on the inlineStyle attribute is incompatible with the autoHeightRows attribute., and should not be done.

      • When the component is placed in a layout-managing container, such as panelSplitter, it will be sized by the container (no auto-sizing will occur). See Geometry Management for the Table, Tree, and Tree Table Components.

    • SelectionListener: Optionally enter an EL expression for a listener that handles selection events. See What You May Need to Know About Programmatically Selecting Nodes.

    • FocusListener: Optionally enter an EL expression for a listener that handles focus events.

    • RowDisclosureListener: Optionally enter an EL expression for a listener method that handles node disclosure events.

  7. Expand the Advanced section and set the following attributes:
  8. To add components to display data in the tree, drag the desired component from the Components window to the nodeStamp facet. Figure 12-29 shows the nodeStamp facet for the tree used to display directories in the File Explorer application.

    Figure 12-29 nodeStamp Facet in the Structure Window

    Description of Figure 12-29 follows
    Description of "Figure 12-29 nodeStamp Facet in the Structure Window"

    The component's value should be bound to the variable value set on the tree's var attribute and the attribute to be displayed. For example, the tree in the File Explorer application uses folder as the value for the var attribute, and displays the name of the directory for each node. Therefore, the value of the output component used to display the directory name is #{folder.name}.

    Tip:

    Facets in a JSP or JSPX page can accept only one child component. Therefore, if you want to use more than one component per node, place the components in a group component that can be the facet's direct child, as shown in Figure 12-29 (facets on a Facelets page can accept more than one child).

What Happens When You Add a Tree to a Page

When you add a tree to a page, JDeveloper adds a nodeStamp facet to stamp out the nodes of the tree. The following example shows the abbreviated code for the tree in the File Explorer application that displays the directory structure.

<af:tree id="folderTree" 
         var="folder"
         binding="#{explorer.navigatorManager.foldersNavigator
                                             .foldersTreeComponent}"
         value="#{explorer.navigatorManager.foldersNavigator.
                                              foldersTreeModel}"
         disclosedRowKeys="#{explorer.navigatorManager.foldersNavigator.
                                              foldersTreeDisclosedRowKeys}"
         rowSelection="single" 
         contextMenuId=":context2"
         selectionListener="#{explorer.navigatorManager.foldersNavigator.
                                              showSelectedFolderContent}">
  <f:facet name="nodeStamp">
    <af:panelGroupLayout>
      <af:image id="folderNodeStampImg" source="#{folder.icon}"
                inlineStyle="vertical-align:middle; margin-right:3px;
                             shortDesc="folder icon"/>
      <af:outputText id="folderNodeStampText" value="#{folder.name}"/>
    </af:panelGroupLayout>
  </f:facet>
</af:tree>

What Happens at Runtime: Tree Component Events

The tree is displayed in a format with nodes indented to indicate their levels in the hierarchy. The user can click nodes to expand them to show children nodes. The user can click expanded nodes to collapse them. When a user clicks one of these icons, the component generates a RowDisclosureEvent event. You can register a custom rowDisclosureListener method to handle any processing in response to the event. See What You May Need to Know About Programmatically Expanding and Collapsing Nodes.

When a user selects or deselects a node, the tree component invokes a selectionEvent event. You can register custom selectionListener instances, which can do post-processing on the tree component based on the selected nodes. See What You May Need to Know About Programmatically Selecting Nodes.

What You May Need to Know About Programmatically Expanding and Collapsing Nodes

The RowDisclosureEvent event has two RowKeySet objects: the RemovedSet object for all the collapsed nodes and the AddedSet object for all the expanded nodes. The component expands the subtrees under all nodes in the added set and collapses the subtrees under all nodes in the removed set.

Your custom rowDisclosureListener method can do post-processing, on the tree component, as shown in the following example.

<af:treeTable id="folderTree" var="directory" value="#{fs.treeModel}"
     binding="#{editor.component}" rowselection="multiple"
     columnselection="multiple" focusRowKey="#{fs.defaultFocusRowKey}"
     selectionListener="#{fs.Table}"
     contextMenuId="treeTableMenu"
     rowDisclosureListener="#{fs.handleRowDisclosure}">

For the contraction of a tree node, you use getRemovedSet in a backing bean method that handles row disclosure events, as shown in the following example that illustrates the expansion of a tree node.

public void handleRowDisclosure(RowDisclosureEvent rowDisclosureEvent)
  throws Exception {
    Object rowKey = null;
    Object rowData = null;
    RichTree tree = (RichTree) rowDisclosureEvent.getSource();
    RowKeySet rks = rowDisclosureEvent.getAddedSet();
 
    if (rks != null) {
        int setSize = rks.size();
        if (setSize > 1) {
            throw new Exception("Unexpected multiple row disclosure  
                                 added row sets found.");
        }
        
        if (setSize == 0) {
           // nothing in getAddedSet indicates this is a node
           // contraction, not expansion. If interested only in handling
           // node expansion at this point, return.
           return;
        }
 
        rowKey = rks.iterator().next();
        tree.setRowKey(rowKey);
        rowData = tree.getRowData();
 
        // Do whatever is necessary for accessing tree node from
        // rowData, by casting it to an appropriate data structure
        // for example, a Java map or Java bean, and so forth.
   }
} 

Trees and tree tables use an instance of the oracle.adf.view.rich.model.RowKeySet class to keep track of which nodes are expanded. This instance is stored as the disclosedRowKeys attribute on the component. You can use this instance to control the expand or collapse state of an node in the hierarchy programmatically, as shown in the following example. Any node contained by the RowKeySet instance is expanded, and all other nodes are collapsed. The addAll() method adds all elements to the set, and the and removeAll() method removes all the nodes from the set.

<af:tree var="node"
         inlineStyle="width:90%; height:300px"
         id="displayRowTable"
         varStatus="vs"
         rowselection="single"
         disclosedRowKeys="#{treeTableTestData.disclosedRowKeys}"
         value="#{treeTableTestData.treeModel}">

The backing bean method that handles the disclosed row keys is shown in the following example].

public RowKeySet getDisclosedRowKeys()
{
  if (disclosedRowKeys == null)
  {
    // Create the PathSet that we will use to store the initial
    // expansion state for the tree
      RowKeySet treeState = new RowKeySetTreeImpl();
      // RowKeySet requires access to the TreeModel for currency.
      TreeModel model = getTreeModel();
      treeState.setCollectionModel(model);
      // Make the model point at the root node
      int oldIndex = model.getRowIndex();
      model.setRowKey(null);
      for(int i = 1; i<=19; ++i)
      {
        model.setRowIndex(i);
        treeState.setContained(true);
      }
      model.setRowIndex(oldIndex);
      disclosedRowKeys = treeState;
  }
  return disclosedRowKeys;
}

What You May Need to Know About Programmatically Selecting Nodes

The tree and tree table components allow nodes to be selected, either a single node only, or multiple nodes. If the component allows multiple selections, users can select multiple nodes using Control+click and Shift+click operations.

When a user selects or deselects a node, the tree component fires a selectionEvent event. This event has two RowKeySet objects: the RemovedSet object for all the deselected nodes and the AddedSet object for all the selected nodes.

Tree and tree table components keep track of which nodes are selected using an instance of the class oracle.adf.view.rich.model.RowKeySet. This instance is stored as the selectedRowKeys attribute on the component. You can use this instance to control the selection state of a node in the hierarchy programmatically. Any node contained by the RowKeySet instance is deemed selected, and all other nodes are not selected. The addAll() method adds all nodes to the set, and the and removeAll() method removes all the nodes from the set. Tree and tree table node selection works in the same way as table row selection. You can refer to sample code for table row selection in What You May Need to Know About Performing an Action on Selected Rows in Tables.

Displaying Data in Tree Tables

The ADF Tree Table component can display content in a hierarchical structure. Using this component you can display the content more elaborately than by using a tree component.

The ADF Faces tree table component displays hierarchical data in the form of a table. The display is more elaborate than the display of a tree component, because the tree table component can display columns of data for each tree node in the hierarchy. The component includes mechanisms for focusing on subtrees within the main tree, as well as expanding and collapsing nodes in the hierarchy. Figure 12-30 shows the tree table used in the File Explorer application. Like the tree component, the tree table can display the hierarchical relationship between the files in the collection. And like the table component, it can also display attribute values for each file.

Figure 12-30 Tree Table in the File Explorer Application

Description of Figure 12-30 follows
Description of "Figure 12-30 Tree Table in the File Explorer Application"

The immediate children of a tree table component must be column components, in the same way as for table components. Unlike the table, the tree table component has a nodeStamp facet which holds the column that contains the primary identifier of an node in the hierarchy. The treeTable component supports the same stamping behavior as the Tree component (see Displaying Data in Trees).

Note:

The nodeStamp facet can only contain one column (which becomes the node in the tree).

For example, in the File Explorer application (as shown in Figure 12-30), the primary identifier is the file name. This column is what is contained in the nodeStamp facet. The other columns, such as Type and Size, display attribute values on the primary identifier, and these columns are the direct children of the tree table component. This tree table uses node as the value of the variable that will be used to stamp out the data for each node in the nodeStamp facet column and each component in the child columns. The following example shows abbreviated code for the tree table in the File Explorer application.

<af:treeTable id="folderTreeTable" var="file"
              value="#{explorer.contentViewManager.treeTableContentView.
                                                   contentModel}"
              binding="#{explorer.contentViewManager.treeTableContentView.
                                                   contentTreeTable}"
              emptyText="#{explorerBundle['global.no_row']}"
              columnStretching="last"
              rowSelection="single"
              selectionListener="#{explorer.contentViewManager.
                                   treeTableContentView.treeTableSelectFileItem}"
              summary="treeTable data">
  <f:facet name="nodeStamp">
    <af:column headerText="#{explorerBundle['contents.name']}"
               width="200" sortable="true" sortProperty="name">
      <af:panelGroupLayout>
        <af:image source="#{file.icon}"
                  shortDesc="#{file.name}"
                  inlineStyle="margin-right:3px; vertical-align:middle;"/>
        <af:outputText id="nameStamp" value="#{file.name}"/>
      </af:panelGroupLayout>
    </af:column>
  </f:facet>
  <f:facet name="pathStamp">
    <af:panelGroupLayout>
      <af:image source="#{file.icon}"
                shortDesc="#{file.name}"
                inlineStyle="margin-right:3px; vertical-align:middle;"/>
      <af:outputText value="#{file.name}"/>
    </af:panelGroupLayout>
  </f:facet>
  <af:column headerText="#{explorerBundle['contents.type']}">
    <af:outputText id="typeStamp" value="#{file.type}"/>
  </af:column>
  <af:column headerText="#{explorerBundle['contents.size']}">
    <af:outputText id="sizeStamp" value="#{file.property.size}"/>
  </af:column>
  <af:column headerText="#{explorerBundle['contents.lastmodified']}"
             width="140">
    <af:outputText id="modifiedStamp"
                   value="#{file.property.lastModified}"/>
  </af:column>
</af:treeTable>

The tree table component supports many of the same attributes as both tables and trees. For additional information about these attributes see Displaying Data in Tables and Displaying Data in Trees.

How to Display Data in a Tree Table

You use the Insert Tree Table wizard to create a tree table. Once the wizard is complete, you can use the Properties window to configure additional attributes on the tree table.

Before you begin:

It may be helpful to have an understanding of how the attributes can affect functionality. See Displaying Data in Tree Tables.

You may also find it helpful to understand functionality that can be added using other ADF Faces features. See Additional Functionality for Collection-Based Components.

To add a tree table to a page:

  1. In the Components window, from the Data Views panel, drag and drop a Tree Table onto the page to open the Insert Tree Table wizard.
  2. Configure the table by completing the wizard. For help with the wizard, click Help or press F1.
  3. Use the Properties window to configure any other attributes.

    Tip:

    The attributes of the tree table are the same as those on the table and tree components. Refer to How to Display a Table on a Page, and How to Display Data in Trees for help in configuring the attributes.

Passing a Row as a Value

The ADF allows you to pass the data of an entire row of a table or a tree residing on another page within the framework. You can achieve this by using the setPropertyListener tag. This is helpful when you want to retrieve the data in a table by a click of a button.

There may be a case where you need to pass an entire row from a collection as a value. To do this, you pass the variable used in the table to represent the row, or used in the tree to represent a node, and pass it as a value to a property in the pageFlow scope. Another page can then access that value from the scope. The setPropertyListener tag allows you to do this (for more information about the setPropertyListener tag, including procedures for using it, see Passing Values Between Pages).

For example, suppose you have a master page with a single-selection table showing employees, and you want users to be able to select a row and then click a button to navigate to a new page to edit the data for that row, as shown in the following example. The EL variable name emp is used to represent one row (employee) in the table. The action attribute value of the button component is a static string outcome showEmpDetail, which allows the user to navigate to the Employee Detail page. The setPropertyListener tag takes the from value (the variable emp), and stores it with the to value.

<af:table value="#{myManagedBean.allEmployees}" var="emp"
          rowSelection="single">
  <af:column headerText="Name">
    <af:outputText value="#{emp.name}"/>
  </af:column>
  <af:column headerText="Department Number">
    <af:outputText value="#{emp.deptno}"/>
  </af:column>
  <af:column headertext="Select">
    <af:button text="Show more details" action="showEmpDetail">
      <af:setPropertyListener from="#{emp}" 
                              to="#{pageFlowScope.empDetail}" 
                              type="action"/>
    </af:button>
  </af:column>
</af:table> 

When the user clicks the button on an employee row, the listener executes, and the value of #{emp} is retrieved, which corresponds to the current row (employee) in the table. The retrieved row object is stored as the empDetail property of pageFlowScope with the #{pageFlowScope.empDetail} EL expression. Then the action event executes with the static outcome, and the user is navigated to a detail page. On the detail page, the outputText components get their value from pageFlowScope.empDetail objects, as shown in the following example.

<h:panelGrid columns="2">
  <af:outputText value="Firstname:"/>
  <af:inputText value="#{pageFlowScope.empDetail.name}"/>
  <af:outputText value="Email:"/>
  <af:inputText value="#{pageFlowScope.empDetail.email}"/>
  <af:outputText value="Hiredate:"/>
  <af:inputText value="#{pageFlowScope.empDetail.hiredate}"/>
  <af:outputText value="Salary:"/>
  <af:inputText value="#{pageFlowScope.empDetail.salary}"/>
</h:panelGrid> 

Displaying Table Menus, Toolbars, and Status Bars

Using ADF panelCollection component you can add menus, toolbars, and status bars to a table. You can also add actions, such as expanding or collapsing the content, detaching the toolbar from the tree or tree table, and so on.

You can use the panelCollection component to add menus, toolbars, and status bars to tables, trees, and tree tables. To use the panelCollection component, you add the table, tree, or tree table component as a direct child of the panelCollection component. The panelCollection component provides default menus and toolbar buttons.

Figure 12-31 shows the panelCollection component with the tree table component in the File Explorer application. The toolbar contains a menu that provides actions that can be performed on the tree table (such as expanding and collapsing nodes), a button that allows users to detach the tree table, and buttons that allow users to change the rows displayed in the tree table. You can configure the toolbar to not display certain toolbar items. For example, you can turn off the buttons that allow the user to detach the tree or table. For information about menus, toolbars, and toolbar buttons, see Using Menus, Toolbars, and Toolboxes.

Figure 12-31 Panel Collection for Tree Table with Menus and Toolbar

Description of Figure 12-31 follows
Description of "Figure 12-31 Panel Collection for Tree Table with Menus and Toolbar"

Among other facets, the panelCollection component contains a menu facet to hold menu components, a toolbar facet for toolbar components, a secondaryToolbar facet for another set of toolbar components, and a statusbar facet for status items.

The default top-level menu and toolbar items vary depending on the component used as the child of the panelCollection component:

  • Table and tree: Default top-level menu is View.

  • Table and tree table with selectable columns: Default top-level menu items are View and Format.

  • Table and tree table: Default toolbar menu is Detach.

  • Table and tree table with selectable columns: Default top-level toolbar items are Freeze, Detach, and Wrap

  • Tree and tree table (when the pathStamp facet is used): The toolbar buttons Go Up, Go To Top, and Show as Top also appear.

The following example shows how the panelCollection component contains menus and toolbars.

<af:panelCollection
    binding="#{editor.component}">  
  <f:facet name="viewMenu">
    <af:group>
      <af:commandMenuItem text="View Item 1..."/>
      <af:commandMenuItem text="View Item 2.."/>
      <af:commandMenuItem text="View Item 3..." disabled="true"/>
      <af:commandMenuItem text="View Item 4"/>
    </af:group>
  </f:facet>

  <f:facet name="menus">
    <af:menu text="Actions">
      <af:commandMenuItem text="Add..." />
      <af:commandMenuItem text="Create.." />
      <af:commandMenuItem text="Update..." disabled="true"/>
      <af:commandMenuItem text="Copy"/>
      <af:commandMenuItem text="Delete"/>              
      <af:commandMenuItem text="Remove" accelerator="control A"/>
      <af:commandMenuItem text="Preferences"/>
    </af:menu>
  </f:facet>
  <f:facet name="toolbar">
    <af:toolbar>
      <af:button shortDesc="Create" icon="/new_ena.png">
      </af:button>
      <af:button shortDesc="Update" icon="/update_ena.png">
      </af:button>
      <af:button shortDesc="Delete" icon="/delete_ena.png">
      </af:button>
    </af:toolbar>
  </f:facet>
  <f:facet name="secondaryToolbar">
  </f:facet>
  <f:facet name="statusbar">
    <af:toolbar>
      <af:outputText id="statusText" ... value="Custom Statusbar Message"/>
    </af:toolbar>
  </f:facet>
  <af:table rowselection="multiple" columnselection="multiple" 
                        ...
  <af:column 
                        ...
  </af:column>

Tip:

You can make menus detachable in the panelCollection component. See Using Menus in a Menu Bar. Consider using detached menus when you expect users to do any of the following:

  • Execute similar commands repeatedly on a page.

  • Execute similar commands on different rows of data in a large table, tree table, or tree.

  • View data in long and wide tables or tree tables, and trees. Users can choose which columns or branches to hide or display with a single click.

  • Format data in long or wide tables, tree tables, or trees.

How to Add a panelCollection with a Table, Tree, or Tree Table

You add a panelCollection component and then add the table, tree, or tree table inside the panelCollection component. You can then add and modify the menus and toolbars for it.

Before you begin:

It may be helpful to have an understanding of how the attributes can affect functionality. See Displaying Table Menus, Toolbars, and Status Bars.

You may also find it helpful to understand functionality that can be added using other ADF Faces features. See Additional Functionality for Collection-Based Components.

To create a panelCollection component with an aggregate display component:

  1. In the Components window, from the Layout panel, drag and drop a Panel Collection onto the page. Add the table, tree, or tree table as a child to that component.

    Alternatively, if the table, tree, or tree table already exists on the page, you can right-click the component and choose Surround With. Then select Panel Collection to wrap the component with the panelCollection component.

  2. Optionally, customize the panelCollection toolbar by turning off specific toolbar and menu items. To do so, select the panelCollection component in the Structure window. In the Properties window, set the featuresOff attribute. Table 12-1 shows the valid values and the corresponding effect on the toolbar.

    Table 12-1 Valid Values for the featuresOff Attribute

    Value Will not display...

    statusBar

    status bar

    viewMenu

    View menu

    formatMenu

    Format menu

    columnsMenuItem

    Columns menu item in the View menu

    columnsMenuItem:colId

    For example:columnsMenuItem:col1, col2

    Columns with matching IDs in the Columns menu

    For example, the value to the left would not display the columns whose IDs are col1 and col2

    freezeMenuItem

    Freeze menu item in the View menu

    detachMenuItem

    Detach menu item in the View menu

    sortMenuItem

    Sort menu item in the View menu

    reorderColumnsMenuItem

    Reorder Columns menu item in the View menu

    resizeColumnsMenuItem

    Resize Columns menu item in the Format menu

    wrapMenuItem

    Wrap menu item in the Format menu

    showAsTopMenuItem

    Show As Top menu item in the tree's View menu

    scrollToFirstMenuItem

    Scroll To First menu item in the tree's View menu

    scrollToLastMenuItem

    Scroll To Last menu item in the tree's View menu

    freezeToolbarItem

    Freeze toolbar item

    detachToolbarItem

    Detach toolbar item

    wrapToolbarItem

    Wrap toolbar item

    showAsTopToolbarItem

    Show As Top toolbar item

    wrap

    Wrap menu and toolbar items

    freeze

    Freeze menu and toolbar items

    detach

    Detach menu and toolbar items

  3. Add your custom menus and toolbars to the component:
    • Menus: Add a menu component inside the menu facet.

    • Toolbars: Add a toolbar component inside the toolbar or secondaryToolbar facet.

    • Status items: Add items inside the statusbar facet.

    • View menu: Add commandMenuItem components to the viewMenu facet. For multiple items, use the group component as a container for the commandMenuItem components.

    From the Components window, drag and drop the component into the facet. For example, drop Menu into the menu facet, then drop Menu Items into the same facet to build a menu list. For instructions about menus and toolbars, see Using Menus, Toolbars, and Toolboxes.

Displaying a Collection in a List

Using the ADF listView and listItem components you can display the contents in a single-column table structure. You can also achieve two-level hierarchy by binding listView to a TreeModel.

Instead of using a table with multiple columns, you can use the listView and listItem components to display structured data in a simple table-like format that contains just one column. Figure 12-32 shows a listView component that contains one listItem component used to display an error icon, task information, and an action button, for each row.

Figure 12-32 The listView Component with a listItem Component

Description of Figure 12-32 follows
Description of "Figure 12-32 The listView Component with a listItem Component"

As shown in Figure 12-33, instead of using columns to group the data to be displayed, a mix of layout components and other components, held by one listItem component, display the actual the data. In this example, the listItem component contains one large panelGroupLayout component set to display its children horizontally. The children are three other panelGroupLayout components used to group their children as columns might in a table. These panelGroupLayout components are also set to display their children horizontally. The second of these layout components contains one panelGroupLayout component set to display its child components (in this case three outputText components) vertically.

Figure 12-33 The listItem Component Contains Multiple Components That Display the Data

Description of Figure 12-33 follows
Description of "Figure 12-33 The listItem Component Contains Multiple Components That Display the Data "

See Example 12-1 below, for the corresponding code.

You bind the listView component to the collection. The component then repeatedly renders one listItem component by stamping the value for each item. As each item is stamped, the data for the current row is copied into a property that can be addressed by an EL expression that uses the listView component's var attribute. Once the list has completed rendering, this property is removed or reverted back to its previous value.

In this example, the listView value is bound to the demolistView.taskModel object. The properties on this object can be accessed using the var property, which is set to item. For example, in order to display the task name, the outputText component value is set to item.taskName.

The listView component can also display a limited, two-level hierarchy. To display a hierarchy, the listView needs to be bound to a TreeModel instead of a CollectionModel. The TreeModel can contain one root level and one child level (for information about the TreeModel class, see Displaying Data in Trees).

As with trees, the listView uses stamping to display content for the individual nodes, and a facet (named the groupHeaderStamp facet) that acts as a holder for the component used to display the parent group for the nodes. However, since the listView only allows two levels, the groupHeaderStamp facet contains the component used to display only the root level.

Figure 12-34 shows a listView component displaying a simple hierarchy that has letters of the alphabet as the root, and employee objects as the leaf nodes.

Figure 12-34 Simple Hierarchy in a listView Component

Description of Figure 12-34 follows
Description of "Figure 12-34 Simple Hierarchy in a listView Component"

The components used to display the employee object are placed in a listItem component, while the components used to display the letter of the alphabet are placed in a listItem component inside the groupHeaderStamp facet, as shown in the following example.

<af:listView id="listView" binding="#{editor.component}"
             var="item" varStatus="vs" groupDisclosurePolicy="noDisclosure"
             value="#{demolistView.ABTreeModel}">
  <af:listItem id="listItem1">
    <af:panelGroupLayout id="pgl3" layout="vertical">
      <af:outputText id="ot2" value="#{item.ename}" styleClass="ABName"/>
      <af:outputText id="ot3" value="#{item.job}" styleClass="ABJob"/>
    </af:panelGroupLayout>
  </af:listItem>
  <f:facet name="groupHeaderStamp">
    <af:listItem id="listItem2" styleClass="ABHeader">
      <af:outputText id="ot1" value="#{item.alphabetHeading}"/>
    </af:listItem>
  </f:facet>
</af:listView>

When you display a hierarchy in a listView component, you can configure it so that the headers can disclose or hide its child components, as shown in Figure 12-35.

Figure 12-35 The listView Component Configured to Provide Collapsing Headers

Description of Figure 12-35 follows
Description of "Figure 12-35 The listView Component Configured to Provide Collapsing Headers"

By default, the listView component is configured to display all children. You can change this using the groupDisclosurePolicy attribute.

When a user collapses or expands a group, a RowDisclosureEvent is fired. You can use the groupDisclosureListener to programmatically expand and collapse nodes. See What You May Need to Know About Programmatically Expanding and Collapsing Nodes.

When a user selects or deselects a row or a node, a SelectionEvent is fired. You can use the selectionListener to programmatically respond to the event. See What You May Need to Know About Performing an Action on Selected Rows in Tables.

Example 12-1 The listView Component

<af:listView id="listView" binding="#{editor.component}"
                           var="item" varStatus="vs" partialTriggers="::pprLV"
                           value="#{demolistView.taskModel}"
                           selection="multiple">
  <af:listItem id="lvi">
    <af:showPopupBehavior popupId="::ctxtMenu"
                          triggerType="contextMenu"/>
    <af:panelGroupLayout id="panelGroupLayout1"
                         layout="horizontal"
                         styleClass="AFStretchWidth">
      <af:panelGroupLayout id="panelGroupLayout2"
                           layout="horizontal"
                           inlineStyle="margin-left:20px; width:45px"
                           halign="center" valign="middle">
        <af:image rendered="#{vs.index %6 ==1}"
                  source="/images/error.png" id="i1"
                  shortDesc="Error at Line #{vs.index + 1}"/>
      </af:panelGroupLayout>
      <af:panelGroupLayout id="panelGroupLayout3" layout="horizontal"
                           inlineStyle="width:100%">
        <af:panelGroupLayout id="panelGroupLayout5"
                             layout="vertical"
                             inlineStyle="min-width:300px">
          <af:outputText id="outputText1" value="#{item.taskName}"
                         styleClass="taskName"/>
          <af:outputText id="outputText2"
                         value="#{item.projectDesc}"
                         styleClass="taskProjectDesc"/>
          <af:outputText id="outputText3" value="#{item.created}"
                         styleClass="taskCreated"/>
        </af:panelGroupLayout>
      </af:panelGroupLayout>
      <af:panelGroupLayout id="panelGroupLayout4"
                           layout="horizontal" halign="end"
                           valign="middle"
                           inlineStyle="margin-right:20px">
        <af:button id="cb1" text="Action"
                      shortDesc="Click To Invoke Action for Item #{vs.index + 1}">
          <af:showPopupBehavior popupId="::popupDialog"
                               alignId="cb1" align="afterStart"/>
        </af:button>
      </af:panelGroupLayout>
    </af:panelGroupLayout>
  </af:listItem>
</af:listView>

How to Display a Collection in a List

You use a listView component bound to a CollectionModel instance and one listItem component to create the list. If you want to display a simple parent-child hearers, you place a second listItem component in the groupHeaderStamp facet. You then add layout components and other text components to display the actual data.

To display a collection in a list:

  1. Create a Java class for the model to which the list will be bound. If you want the list to display groups with headers, the model must extend the org.apache.myfaces.trinidad.model.TreeModel class. If not, it should extend the org.apache.myfaces.trinidad.model.CollectionModel class.

    Tip:

    You may also use other model classes, such as java.util.List, array, and javax.faces.model.DataModel. If you use one of these other classes, the listView component automatically converts the instance into a CollectionModel class, but without any additional functionality. For information about the CollectionModel class, see the MyFaces Trinidad Javadoc at http://myfaces.apache.org/trinidad/trinidad-1_2/trinidad-api/apidocs/index.html.

  2. In the Components window, from the Data Views panel, drag and drop a List View on to the page.
  3. In the Properties window, expand the Other section and set the following:
    • Value: Specify an EL expression to bind the list to the mode created in Step 1.

    • Var: Specify a variable name to represent each node.

    • First: Specify a row to set as the first row to display in the list.

    • FetchSize: Set the size of the block that should be returned with each data fetch. The default is 25.

    • Rows: Specific the number of rows to display in the range of rows. By default this is 25 (the same value as the fetchSize attribute).

    • SelectedRowKeys: Optionally enter the keys for the nodes that should be initially selected. See What You May Need to Know About Programmatically Selecting Nodes.

    • Selection: Set a value to make the rows selectable (this is the rowSelection attribute). Valid values are: none, single, and multiple. For information about how to then programmatically perform some action on the selected rows, see What You May Need to Know About Performing an Action on Selected Rows in Tables.

  4. Drag and drop a List Item as a child to the listView component.
  5. Drag and drop layout and other components into the listView component, to create your desired configuration. See Figure 12-33 and Example 12-1 for an example.
  6. If you want the listView component to display a simple hierarchy, drag and drop a List Item into the groupHeaderStamp facet.Figure 12-36 shows the groupHeaderStamp facet in the Structure window.

    Figure 12-36 The groupHeaderStamp Facet in the Structure Window

    Description of Figure 12-36 follows
    Description of "Figure 12-36 The groupHeaderStamp Facet in the Structure Window"
  7. Drag and drop an Output Text into the listItem component to display your header text, and configure the outputText component as needed.

What You May Need to Know About Scrollbars in a List View

Similar to tables, you can configure the listView component to use scrollbars. When you configure the listView component to use scrolling, in iOS operating systems, by default, the scrollbars only appear when you mouseover the content. Otherwise, they remain hidden. You can configure your application so that this same behavior occurs on other operating systems as well, by adding the -tr-overflow-style: autohiding-scrollbar skinning property to af|listView selector.

af|listView {
  -tr-overflow-style: autohiding-scrollbar
}

Note:

On operating systems other than iOS, initially set style attribute to overflow:hidden for listView root element. For the mouseHover event, set style attribute to overflow:auto and for the mouseOut event set style attribute back to overflow:hidden.

Displaying Images in a Carousel

You can display images in a revolving carousel structure using ADF carouselItem component. You can also configure the display of the carousel structure.

You can display images in a revolving carousel, as shown in Figure 12-37. Users can change the image at the front either by using the slider at the bottom or by clicking one of the auxiliary images to bring that specific image to the front.

Figure 12-37 The ADF Faces Carousel

Description of Figure 12-37 follows
Description of "Figure 12-37 The ADF Faces Carousel"

By default, the carousel displays horizontally. The objects within the horizontal orientation of the carousel are vertically-aligned to the middle and the carousel itself is horizontally-aligned to the center of its container.

You can configure the carousel so that it can be displayed vertically, as you might want for a reference Rolodex. By default, the objects within the vertical orientation of the carousel are horizontally-aligned to the center and the carousel itself is vertically aligned middle, as shown in Figure 12-38. You can change the alignments using the carousel's alignment attributes.

Figure 12-38 Vertical Carousel Component

Description of Figure 12-38 follows
Description of "Figure 12-38 Vertical Carousel Component"

Best Practice:

Generally the carousel should be placed in a parent component that stretches its children (such as a panelSplitter or panelStretchLayout). If you do not place the carousel in a component that stretches its children, your carousel will display at the default dimension of 500px wide and 300px tall. You can change these dimensions.

Instead of partially displaying the previous and next images, you can configure your carousel so that it displays images in a filmstrip design, as shown in Figure 12-39, or in a roomy circular design, as shown in Figure 12-40.

Figure 12-39 Carousel Filmstrip Display

Description of Figure 12-39 follows
Description of "Figure 12-39 Carousel Filmstrip Display"

Figure 12-40 Carousel Roomy Circular Display

Description of Figure 12-40 follows
Description of "Figure 12-40 Carousel Roomy Circular Display"

By default, when the carousel is configured to display in the circular mode, when you hover over an auxiliary item (that is, and item that is not the current item at the center), the item is outlined to show that it can be selected (note that this outline will only appear if your application is using the Skyros and above skins). You can configure the carousel so that instead, the item pops out and displays at full size, as shown in Figure 12-41.

Figure 12-41 Auxiliary Item Pops Out on Hover

Description of Figure 12-41 follows
Description of "Figure 12-41 Auxiliary Item Pops Out on Hover"

You can also configure your carousel so that it displays only the current image, as shown in Figure 12-42.

Figure 12-42 Carousel Can Display Just One Image

Description of Figure 12-42 follows
Description of "Figure 12-42 Carousel Can Display Just One Image"

You can configure the controls used to browse through the images. You can display a slider with next and previous arrows that spans more than one image, display only next and previous buttons, as shown in Figure 12-42, or display next and previous buttons, along with the slide counter, as shown in Figure 12-43.

Figure 12-43 Next and Previous Buttons Without a Slider

Description of Figure 12-43 follows
Description of "Figure 12-43 Next and Previous Buttons Without a Slider"

A child carouselItem component displays the objects in the carousel, along with a title for the object. Instead of creating a carouselItem component for each object to be displayed, and then binding these components to the individual object, you bind the carousel component to a complete collection. The component then repeatedly renders one carouselItem component by stamping the value for each item, similar to the way a tree stamps out each row of data. As each item is stamped, the data for the current item is copied into a property that can be addressed using an EL expression using the carousel component's var attribute. Once the carousel has completed rendering, this property is removed or reverted back to its previous value. Carousels contain a nodeStamp facet, which is both a holder for the carouselItem component used to display the text and short description for each item, and also the parent component to the image displayed for each item.

For example, the carouselItem JSF page in the ADF Faces Components Demo shown in Figure 12-37 contains a carousel component that displays an image of each of the ADF Faces components. The demoCarouselItem (CarouselBean.java) managed bean contains a list of each of these components. The value attribute of the carousel component is bound to the items property on that bean, which represents that list. The carousel component's var attribute is used to hold the value for each item to display, and is used by both the carouselItem component and image component to retrieve the correct values for each item. The following example shows the JSF page code for the carousel. For information about stamping behavior in a carousel, see Displaying Data in Trees.

<af:carousel id="carousel" binding="#{editor.component}"
             var="item"
             value="#{demoCarousel.items}"
             carouselSpinListener="#{demoCarousel.handleCarouselSpin}">
  <f:facet name="nodeStamp">
    <af:carouselItem id="crslItem" text="#{item.title}" shortDesc="#{item.title}">
      <af:image id="img" source="#{item.url}" shortDesc="#{item.title}"/>
    </af:carouselItem>
  </f:facet>
</af:carousel>

A carouselItem component stretches its sole child component. If you place a single image component inside of the carouselItem, the image stretches to fit within the square allocated for the item (as the user spins the carousel, these dimensions shrink or grow).

Best Practice:

The image component does not provide any geometry management controls for altering how it behaves when stretched. You should use images that have equal width and height dimensions in order for the image to retain its proper aspect ratio when it is being stretched.

The carousel component uses a CollectionModel class to access the data in the underlying collection. This class extends the JSF DataModel class and adds on support for row keys. In the DataModel class, rows are identified entirely by index. However, to avoid issues if the underlying data changes, the CollectionModel class is based on row keys instead of indexes.

You may also use other model classes, such as java.util.List, array, and javax.faces.model.DataModel. If you use one of these other classes, the carousel component automatically converts the instance into a CollectionModel class, but without any additional functionality. For information about the CollectionModel class, see the MyFaces Trinidad Javadoc at http://myfaces.apache.org/trinidad/trinidad-1_2/trinidad-api/apidocs/index.html.

Note:

If your application uses the Fusion technology stack, you can create ADF Business Components over your data source that represent the items, and the model will be created for you. You can then declaratively create the carousel, and it will automatically be bound to that model. See the "Using the ADF Faces Carousel Component" section in Developing Fusion Web Applications with Oracle Application Development Framework.

The carousel components are virtualized, meaning not all the items that are there for the component on the server are delivered to and displayed on the client. You configure the carousel to fetch a certain number of rows at a time from your data source. The data can be delivered to the component either immediately upon rendering, or lazily fetched after the shell of the component has been rendered. By default, the carousel lazily fetches data for the initial request. When a page contains one or more of these components, the page initially goes through the standard lifecycle. However, instead of the carousel fetching the data during that initial request, a special separate partial page rendering (PPR) request is run on the component, and the number of items set as the value of the fetch size for the carousel is then returned. Because the page has just been rendered, only the Render Response phase executes for the carousel, allowing the corresponding data to be fetched and displayed. When a user does something to cause a subsequent data fetch (for example spinning the carousel for another set of images), another PPR request is executed.

Performance Tip:

You should use lazy delivery when the page contains a number of components other than a carousel. Using lazy delivery allows the initial page layout and other components to be rendered first before the data is available.

Use immediate delivery if the carousel is the only context on the page, or if the carousel is not expected to return a large set of items. In this case, response time will be faster than using lazy delivery (or in some cases, simply perceived as faster), as the second request will not go to the server, providing a faster user response time and better server CPU utilizations. Note however that only the number of items configured to be the fetch block will be initially returned. As with lazy delivery, when a user's actions cause a subsequent data fetch, the next set of items are delivered.

A slider control allows users to navigate through the collection. Normally the thumb on the slider displays the current object number out of the total number of objects, for example 6 of 20. When the total number of objects is too high to calculate, the thumb on the slider will show only the current object number. For example, say a carousel is used for a company' s employee directory. By default the directory might show faces for every employee, but it may not know without an expensive database call that there are exactly 94,409 employees in the system that day.

You can use other components in conjunction with the carousel. For example, you can add a toolbar or menu bar, and to that, add buttons or menu items that allow users to perform actions on the current object.

How to Create a Carousel

To create a carousel, you must first create the data model that contains the images to display. You then bind a carousel component to that model and insert a carouselItem component into the nodeStamp facet of the carousel. Lastly, you insert an image component (or other components that contain an image component) as a child to the carouselItem component.

Before you begin:

It may be helpful to have an understanding of how the attributes can affect functionality. See Displaying Images in a Carousel.

You may also find it helpful to understand functionality that can be added using other ADF Faces features. See Additional Functionality for Collection-Based Components.

Create the data model that will provide the collection of images to display. The data model can be a List, Array, DataModel or CollectionModel. If the collection is anything other than a CollectionModel, the framework will automatically convert it to a CollectionModel. For information about the CollectionModel class, see the MyFaces Trinidad Javadoc at http://myfaces.apache.org/trinidad/trinidad-1_2/trinidad-api/apidocs/index.html.

The data model should provide the following information for each of the images to be displayed in the carousel:

  • URL to the images

  • Title, which will be displayed below the image in the carousel

  • Short description used for text displayed when the user mouses over the image

For examples, see the CarouselBean.java and the CarouselMediaBean.java classes in the ADF Faces Components Demo application.

To Create a Carousel:

  1. In the Components window, from the Data Views panel, drag and drop a Carousel onto the page.

    Best Practice:

    Place the carousel in a parent container that stretches its children.

  2. In the Properties window, expand the Common section, and set the following:
    • Orientation: By default, the carousel displays horizontally. Select vertical if you want it to display vertically, as shown in Figure 12-38. If you set it to horizontal, you must configure how the items line up using the halign attribute. If you set it to vertical, set how the items line up using the valign attribute.

    • Halign: Specify how you want items in a vertical carousel to display. Valid values are:

      • center: Aligns the items so that they have the same centerpoint. This is the default.

      • end: Aligns the items so that the right edges line up (when the browser is displaying a left-to-right language).

      • start: Aligns the items so that the left edges line up (when the browser is displaying a left-to-right language).

    • Valign: Specify how you want items in a horizontal carousel to display. Valid values are:

      • middle: Aligns the items so that they have the same middle point. This is the default.

      • bottom: Aligns the items so that the bottom edges line up.

      • top: Aligns the items so that the top edges line up.

    • Value: Bind the carousel to the model.

  3. Expand the Data section and set the following:
    • Var: Enter a variable that will be used in EL to access the individual item data.

    • VarStatus: Enter a variable that will be used in EL to access the status of the carousel. Common properties of varStatus include:

      • model: Returns the CollectionModel for the component.

      • index: Returns the zero-based item index.

  4. Expand the Appearance section and set the following:
    • EmptyText: Enter text that should display if no items are returned. If using a resource bundle, use the dropdown menu to choose Select Text Resource.

  5. If you do not place the carousel in a parent component that stretches its children, then the carousel will display at 500px wide by 300px tall. You can change these settings. To do so, expand the Style section, click the Layout tab, and set a height and width in pixels.
  6. Expand the Behavior section, and set the following:
    • FetchSize: Set the size of the block that should be returned with each data fetch.

    • ContentDelivery: Specify when the data should be delivered. When the contentDelivery attribute is set to immediate, items are fetched at the same time the carousel is rendered. If the contentDelivery attribute is set to lazy, items will be fetched and delivered to the client during a subsequent request.

    • CarouselSpinListener: Bind to a handler method that handles the spinning of the carousel when you need logic to be executed when the carousel spin is executed. The following example shows the handler method on the CarouselBean which redraws the detail panel when the spin happens.

        public void handleCarouselSpin(CarouselSpinEvent event)
        {
          RichCarousel carousel = (RichCarousel)event.getComponent();
          carousel.setRowKey(event.getNewItemKey());
          ImageInfo itemData = (ImageInfo)carousel.getRowData();
          _currentImageInfo = itemData;
       
          // Redraw the detail panel so that we can update the selected details.
          RequestContext rc = RequestContext.getCurrentInstance();
          rc.addPartialTarget(_detailPanel);
        }
      
  7. Expand the Advanced section and set CurrentItemKey. Specify which item is showing when the carousel is initially rendered. The value should be (or evaluate to) the item's primary key in the CollectionModel.
  8. Expand the Other section and set the following:
    • AuxiliaryOffset: Enter a value to control the offset shift factor that a carousel item will have relative to its nearest item towards the current carousel item in circular DisplayItems mode.

    • AuxiliaryPopOut: Select hover so that mousing over an auxiliary item will render it at full size with the opaque overlay removed.

    • AuxiliaryScale: Enter a value to control the size scaling factor that a carousel item will have relative to its nearest item towards the current carousel item in circular DisplayItems mode. A value of 1 means the auxiliary items will be the same size. A value less than 1 means the auxiliary items will become smaller the further they are from the current item. A value greater than 1 means the auxiliary items will become larger the further they are from the current item.

    • ControlArea: Specify the controls used to browse through the carousel images. Valid values are:

      • full: A slider displays with built-in next and previous buttons, the current item text, and the image number. This is the default.

      • compact: Only the next and previous buttons and item text are displayed.

      • small: Next and previous buttons are displayed, along with the current item text, and the image number.

      • none: No slider is displayed.

    • DisplayItems: Select circular to have the carousel display multiple images. Select oneByOne to have the carousel display one image at a time.

      Tip:

      To achieve a roomy circular design for the DisplayItems in circular mode, set the AuxiliaryScale to 0.8 and AuxiliaryOffset 0.8. To display items in a filmstrip design in circular mode, set AuxiliaryScale to 1.0 and AuxiliaryOffset to 1.1.

  9. In the Components window, from the Data Views panel, drag a Carousel Item to the nodeStamp facet of the Carousel component.

    Bind the CarouselItem component's attributes to the properties in the data model using the variable value set on the carousel's var attribute. For example, if you use item as the value for the var attribute, the value of the carouselItem's text attribute would be item.title (given that title is the property used to access the text used for the carousel items on the data model).

  10. In the Components window, from the General Controls panel, drag an image and drop it as a child to the carouselItem.

    Bind the image component's attributes to the properties in the data model using the variable value set on the carousel's var attribute. For example, if the carousel uses item as the value for the var attribute, the value of the image's source attribute would be item.url (given that url is the property used to access the image).

    You can surround the image component with other components if you want more functionality. For example, Figure 12-44 shows a carousel whose images are surrounded by a panelGroupLayout component and that also uses a clientListener to call a JavaScript function to show a menu and a navigation bar.

    Figure 12-44 Using a More Complex Layout in a Carousel

    Description of Figure 12-44 follows
    Description of "Figure 12-44 Using a More Complex Layout in a Carousel"

    The following example shows the corresponding page code.

    <af:carouselItem id="mainItem" text="#{item.title}" shortDesc="#{item.title}">
      <af:panelGroupLayout id="itemPgl" layout="vertical">
        <af:image id="mainImg" source="#{item.url}" shortDesc="#{item.title}"
                               styleClass="MyImage">
          <af:clientListener method="handleItemOver" type="mouseOver"/>
          <af:clientListener method="handleItemDown" type="mouseDown"/>
          <af:showPopupBehavior triggerType="contextMenu" popupId="::itemCtx"/>
        </af:image>
      <af:panelGroupLayout id="overHead" styleClass="MyOverlayHeader"
                           layout="vertical" clientComponent="true">
        <af:menuBar id="menuBar">
          <af:menu id="menu" text="Menu">
            <af:commandMenuItem id="menuItem1" text="Menu Item 1"/>
            <af:commandMenuItem id="menuItem2" text="Menu Item 2"/>
            <af:commandMenuItem id="menuItem3" text="Menu Item 3"/>
          </af:menu>
        </af:menuBar>
      </af:panelGroupLayout>
      <af:panelGroupLayout id="overFoot" styleClass="MyOverlayFooter"
                           layout="vertical" clientComponent="true"
                           halign="center">
        <af:panelGroupLayout id="footHorz" layout="horizontal">
          <f:facet name="separator">
            <af:spacer id="footSp" width="8"/>
          </f:facet>
          <af:link . . .
                              />
          <af:outputText id="pageInfo" value="Page 1 of 1"/>
          <af:link . . .
                             />
          </af:panelGroupLayout>
        </af:panelGroupLayout>
      </af:panelGroupLayout>
    </af:carouselItem>
    

    The following example shows the corresponding JavaScript.

    function handleItemOver(uiInputEvent)
    {
      var imageComponent = uiInputEvent.getCurrentTarget();
      var carousel = null;
      var componentParent = imageComponent.getParent();
      while (componentParent != null)
      {
        if (componentParent instanceof AdfRichCarousel)
        {
          carousel = componentParent;
        }
        componentParent = componentParent.getParent();
      }
      if (carousel == null)
      {
        AfLogger.LOGGER.severe("Unable to find the carousel component!");
        return;
      }
      var currentItemKeyPattern = ":"+ carousel.getCurrentItemKey() +":";
     
    var overlayHeaderComponent = imageComponent.findComponent("overHead");
    var overlayHeaderId = overlayHeaderComponent.getClientId();
    // In IE we get mouseover for other items as well. This is despite having an
    // overlay div on top
    if(overlayHeaderId.indexOf(currentItemKeyPattern) == -1)
    return;
    if (overlayHeaderId != window._myHeader)
    {
      // ensure only one set of overlays are visible
      hideExistingOverlays();
    }
    var overlayFooterComponent = imageComponent.findComponent("overFoot");
     
    window._myHeader = overlayHeaderComponent.getClientId();
    window._myFooter = overlayFooterComponent.getClientId();
     
    // do not propagate to the server otherwise all stamps will get this property on
    // next data fetch
    overlayHeaderComponent.setProperty("inlineStyle", "display:block", false, AdfUIComponent.PROPAGATE_LOCALLY);
              overlayFooterComponent.setProperty("inlineStyle", "display:block", false, AdfUIComponent.PROPAGATE_LOCALLY);
    }
     
    function handleItemDown(uiInputEvent)
      {
        if (uiInputEvent.isLeftButtonPressed())
        {
          // Only hide the overlays if the left button was pressed
          hideExistingOverlays();
        }
      }
     

    Performance Tip:

    The simpler the structure for the carousel, the faster it will perform.

What You May Need to Know About the Carousel Component and Different Browsers

In some browsers, the visual decoration of the carousel's items will be richer. For example, Safari and Google Chrome display subtle shadows around the carousel's items, and the noncurrent items have a brightness overlay to help make clear that the auxiliary items are not the current item, as shown in Figure 12-45.

Figure 12-45 Carousel Component Displayed in Google Chrome

Description of Figure 12-45 follows
Description of "Figure 12-45 Carousel Component Displayed in Google Chrome"

Figure 12-46 shows the same component in Internet Explorer.

Figure 12-46 Carousel Component Displayed in Microsoft Internet Explorer

Description of Figure 12-46 follows
Description of "Figure 12-46 Carousel Component Displayed in Microsoft Internet Explorer"

Exporting Data from Table, Tree, or Tree Tables

You can export data from ADF Gantt chart to an Excel spreadsheet or you can export as a comma-separated values file. The formatting information is also exported along with data.

You can export the data from a table, tree, or tree table, or from a table region of the data visualization project Gantt chart to a Microsoft Excel spreadsheet or to a comma-separated values (CSV) file. To allow users to export a table, you create an action source, such as a button or link that will be used to invoke the export, and add an exportCollectionActionListener component and associate it with the data you wish to export. The formatting information is included in the exported Excel spreadsheet, so that the data types are identified correctly and you can use the inbuilt functions of the MS Excel on various columns. However, if the cell format is not valid, then by default the text is exported as Text format. You can configure the exportCollectionActionListener so that all the rows of the source table or tree will be exported, or so that only the rows selected by the user will be exported.

Tip:

You can also export data from a DVT pivot table. See Exporting from a Pivot Table.

For example, Figure 12-47 shows the table from the ADF Faces Components Demo application that includes buttons that allow users to export the data to an Excel spreadsheet or as a CSV file.

Figure 12-47 Table with Buttons for Exporting Data

Description of Figure 12-47 follows
Description of "Figure 12-47 Table with Buttons for Exporting Data"

When the user clicks a button, the listener processes the exporting of all the rows to a spreadsheet or CSV. As shown in Figure 12-47, you can also configure the exportCollectionActionListener component so that only the rows the user selects are exported.

Only the following can be exported:

  • Value of value holder components (such as input and output components).

  • Value of selectItem components used in selelctOneChoice and selectOneListbox components (the value of selectItem components in other selection components are not exported).

  • Value of the text attribute of a command component.

  • Value of the shortDesc attribute on image and icon components.

If you do not want the value of the shortDesc attribute on image and icon components to be exported (for example, if a cell contains an image), you can use the predefined skipObjectComponent filter method. This method will run before the exportCollectionActionListener, and will keep any Object components from being exported. You can also create your own custom filter method to apply any needed logic before the exportCollectionActionListener runs.

Depending on the browser, and the configuration of the listener, the browser will either open a dialog, allowing the user to either open or save the file as shown in Figure 12-48, or the file will be displayed in the browser. For example, if the user is viewing the page in Microsoft Internet Explorer, and no file name has been specified on the exportCollectionActionListener component, the file is displayed in the browser. In Mozilla Firefox, the dialog opens.

Figure 12-48 Exporting to Excel Dialog

Description of Figure 12-48 follows
Description of "Figure 12-48 Exporting to Excel Dialog"

If the user chooses to save the file, it can later be opened in a spreadsheet application, as shown in Figure 12-49. If the user chooses to open the file, what happens depends on the browser. For example, if the user is viewing the page in Microsoft Internet Explorer and is exporting a spreadsheet, the spreadsheet opens in the browser window. If the user is viewing the page in Mozilla Firefox, the spreadsheet opens in Excel.

Figure 12-49 Exported Data File in Excel

Description of Figure 12-49 follows
Description of "Figure 12-49 Exported Data File in Excel"

Note:

For spreadsheets, you may receive a warning from Excel stating that the file is in a different format than specified by the file extension. This warning can be safely ignored.

How to Export Table, Tree, or Tree Table Data to an External Format

You create a command component, such as a button, link, or menu item, and add the exportCollectionActionListener inside this component. Then you associate the data collection you want to export by setting the exportCollectionActionListener component's exportedId attribute to the ID of the collection component whose data you wish to export.

Before you begin:

It may be helpful to have an understanding of how the attributes can affect functionality. See Exporting Data from Table, Tree, or Tree Table.

You may also find it helpful to understand functionality that can be added using other ADF Faces features. See Additional Functionality for Collection-Based Components.

You should already have a table, tree, or tree table on your page. If you do not, follow the instructions in this chapter to create a table, tree, or tree table. For example, to add a table, see Displaying Data in Tables.

Tip:

If you want users to be able to select rows to export, then configure your table to allow selection. See Formatting Tables.

To export collection data to an external format:

  1. In the Components window, from the General Controls panel, drag and drop a command component, such as a button, to your page.

    Tip:

    If you want your table, tree, or tree table to have a toolbar that will hold command components, you can wrap the collection component in a panelCollection component. This component adds toolbar functionality. See Displaying Table Menus, Toolbars, and Status Bars.

    You may want to change the default label of the command component to a meaningful name such as Export to a Spreadsheet.

  2. In the Components window, from the Operations panel, drag an Export Collection Action Listener as a child to the command component.
  3. In the Insert Export Collection Action Listener dialog, set the following:
    • ExportedId: Specify the ID of the table, tree, or tree table to be exported. Either enter it manually or use the dropdown menu to choose Edit. Use the Edit Property dialog to select the component.

    • Type: Set to excelHTML to export to an Microsoft Excel spreadsheet. Set to CSV to export to a comma-separated values file.

  4. With the exportCollectionActionListener component still selected, in the Properties window, set the following:
    • Filename: Specify the proposed file name for the exported content. When this attribute is set, a "Save File" dialog will typically be displayed, though this is ultimately up to the browser. If the attribute is not set, the content will typically be displayed inline, in the browser, if possible.

    • Title: Specify the title of the exported document. Whether or not the title is displayed and how exactly it is displayed depends on the spreadsheet application.

    • ExportedRows: Specify if you want to export all rows in the table, or only rows selected by the user. If your table uses the detailStamp facet, you can elect to either export that data or not (for information about the detailStamp facet, see Adding Hidden Capabilities to a Table). Set to one of the following:

      • all: All rows will be exported. This includes the currently visible rows and all hidden rows that have not been disclosed in the component UI.

      • allWithoutDetails: All rows, except the data in the detailStamp facet, will be exported.

      • disclosed: Only the rows as currently displayed in the page will be exported. That includes disclosed (shown) nodes plus their leaf nodes.

      • disclosedWithoutDetails: Only the rows as currently displayed in the page will be exported, except for the data in the detailStamp facet.

      • selected: Only the rows the user has selected will be exported. Set only if the underlying collection supports selection.

      • selectedWithoutDetails: Only the rows the user has selected will be exported, except for the data in the detailStamp facet. Set only if the underlying collection supports selection.

    • RowLimit: Enter a number that represents the maximum number of rows that can be exported. Enter -1 if there should be no limit.

    • Charset: By default, UTF-8 is used. You can specify a different character set if needed.

    • FilterName: Enter skipObjectComponent, if you want a built-in method to run that will skip any Object component from being processed.

    • FilterMethod: Enter an EL expression that evaluates to a method that will be invoked before the ExportCollectionActionListener that will handle any needed override logic.

The following example shows the code for a table and its exportCollectionActionListener component. Note that the exportedId value is set to the table id value.

<af:table contextMenuId="thePopup" selectionListener="#{fs.Table}"
          rowselection="multiple" columnselection="multiple"
          columnBandingInterval="1"
          binding="#{editor.component}" var="test1" value="#{tableTestData}"
          id="table" summary="table data">
  <af:column>
  . . .
  </af:column>
</af:table>
<af:button text="Export To Excel" immediate="true">
  <af:exportCollectionActionListener type="excelHTML" exportedId="table"
                               filename="export.xls" title="ADF Faces Export"/>

What Happens at Runtime: How Row Selection Affects the Exported Data

Exported data is exported in index order, not selected key order. This means that if you allow selected rows to be exported, and the user selects rows (in this order) 8, 4, and 2, then the rows will be exported and displayed in Excel in the order 2, 4, 8.

Accessing Selected Values on the Client from Collection-Based Components

In the ADF framework, the client-support for EL is not available. To access row-specific data on the client, you must use EL on the collection-based component.

Since there is no client-side support for EL in the ADF Faces framework, nor is there support for sending entire collection models to the client, if you need to access values on the client using JavaScript, the client-side code cannot rely on component stamping to access the value. Instead of reusing the same component instance on each row, a new JavaScript component is created on each row (assuming any component needs to be created at all for any of the rows), using the fully resolved EL expressions.

Therefore, to access row-specific data on the client, you need to use the collection-based component itself to access the value. To do this without a client-side data model, you use a client-side selection change listener.

How to Access Values from a Selection in Stamped Components.

To access values on the client from a collection-based component, you first need to make sure the component has a client representation. Then you need to register a selection change listener on the client and then have that listener handle determining the selected row, finding the associated stamped component for that row, use the collection component to determine the row-specific name, and finally interact with the selected data as needed.

Before you begin:

You may also find it helpful to understand functionality that can be added using other ADF Faces features. See Additional Functionality for Collection-Based Components.

To access selected values from collection-based components:

  1. In the Structure window for your page, select the component associated with the stamped row. For example, in the following example the table uses an outputText component to display the stamped rows.
    <af:table var="row" value="#{data}" rowSelection="single">
      <af:column headerText="Name">
        <af:outputText value="#{row.name}"/>
      </af:column>
    </af:table>
    

    Set the following on the component:

    • Expand the Common section of the Properties window and if one is not already defined, set a unique ID for the component using the Id attribute.

    • Expand the Advanced section and set ClientComponent to True.

  2. In the Components window, from the Operations panel, drag and drop a Client Listener as a child to the collection component.
  3. In the Insert Client Listener dialog, enter a function name in the Method field (you will implement this function in the next step), and select selection from the Type dropdown.

    If for example, you entered mySelectedRow as the function, JDeveloper would enter the code shown in bold in the following example.

    <af:table var="row" value="#{data}" rowSelection="single">
      <af:clientListener type="selection" method="mySelectedRow"/>
      ...
    </af:table>
    

    This code causes the mySelectedRow function to be called any time the selection changes.

  4. In your JavaScript library, implement the function entered in the last step. This function should do the following:
    • Figure out what row was selected. To do this, use the event object that is passed into the listener. In the case of selection events, the event object is of type AdfSelectionEvent. This type provides access to the newly selected row keys via the getAddedSet() method, which returns a POJSO (plain old JavaScript object) that contains properties for each selected row key. Once you have access to this object, you can iterate over the row keys using a "for in" loop. For example, the code in the following example extracts the first row key (which in this case, is the only row key).

      function showSelectedName(event)
      {
        var firstRowKey;
        var addRowKeys=event.getAddedSet();
      
        for(var rowKey in addedRowKeys)
        {
          firstRowKey=rowKey;
          break;
        }
      }
      
    • Find the stamped component associated with the selected row. The client-side component API AdfUIComponent exposes a findComponent() method that takes the ID of the component to find and returns the AdfUIComponent instance. When using stamped components, you need to find a component not just by its ID, but by the row key as well. In order to support this, the AdfUITable class provides an overloaded method of findComponent(), which takes both an ID as well as a row key.

      In the case of selection events, the component is the source of the event. So you can get the collection component from the source of the event and then use the collection component to find the instance using the ID and row key. The following example shows this, where nameStamp is the ID of the table.

      // The table needs to find the stamped component.
      // Fortunately, in the case of selection events, the
       // table is the event source.
       var table = event.getSource();
       
       // Use the table to find the name stamp component by id/row key:
       var nameStamp = table.findComponent("nameStamp", firstRowKey);
      
  5. Add any additional code needed to work with the component. Once you have the stamped component, you can interact with it as you would with any other component. For example, the following code shows how to use the stamped component to get the row-specific value of the name attribute and then display the name in an alert.
    if (nameStamp)
      {    // This is the row-specific name
        var name = nameStamp.getValue();
    
        alert("The selected name is: " + name);
      }
    

The following example shows the entire code for the JavaScript.

function showSelectedName(event)
{
  var firstRowKey;
  var addedRowKeys = event.getAddedSet();

  for (var rowKey in addedRowKeys)
  {
    firstRowKey = rowKey;
    break;
  }
  // The table needs to find the stamped component.
  // Fortunately, in the case of selection events, the
  // table is the event source.
  var table = event.getSource();
 
  // We use the table to find the name stamp component by id/row key:
  var nameStamp = table.findComponent("nameStamp", firstRowKey);
 
  if (nameStamp)
  {
    // This is the row-specific name
    var name = nameStamp.getValue();
 
     alert("The selected name is: " + name);
  }
}

What You May Need to Know About Accessing Selected Values

Row keys are tokenized on the server, which means that the row key on the client may have no resemblance to the row key on the server. As such, only row keys that are served up by the client-side APIs (like AdfSelectionEvent.getAddedSet()) are valid.

Also note that AdfUITable.findComponent(id, rowKey)method may return null if the corresponding row has been scrolled off screen and is no longer available on the client. Always check for null return values from AdfUITable.findComponent() method.