Skip Headers
Oracle® Fusion Middleware Java EE Developer's Guide for Oracle Application Development Framework
11g Release 2 (11.1.2.1.0)

Part Number E17272-02
Go to Documentation Home
Home
Go to Table of Contents
Contents
Go to Feedback page
Contact Us

Go to previous page
Previous
Go to next page
Next
PDF · Mobi · ePub

6 Displaying Master-Detail Data

This chapter describes how to create various types of pages that display master-detail related data.

This chapter includes the following sections:

For information about using a selection list to populate a collection with a key value from a related master or detail collection, see Chapter 7, "Creating Databound Selection Lists."

6.1 Introduction to Displaying Master-Detail Data

When objects have a master-detail relationship, you can declaratively create pages that display the data from both objects simultaneously. For example, the page shown in Figure 6-1 displays a country code in a form at the top of the page and its related states and provinces in a table at the bottom of the page. This is possible because the objects have a master-detail relationship. In this example, the Country Code is the master object and States is the detail object. ADF iterators automatically manage the synchronization of the detail data objects displayed for a selected master data object. Iterator bindings simplify building user interfaces that allow scrolling and paging through collections of data and drilling-down from summary to detail information.

Figure 6-1 Detail Table

This shows a Master Form Detail table.

You display master and detail objects in forms and tables. The master-detail form can display these objects on separate pages. For example, you can display the master object in a table on one page and detail objects in a read-only form on another page.

Note:

There are some cases when the master-detail UI components that JDeveloper provides cannot provide the functionality you require. For example, you may need to bind components programatically instead of using the master-detail UI components.

A master object can have many detail objects, and each detail object can in turn have its own detail objects, down to many levels of depth. If one of the detail objects in this hierarchy is dropped from the Application Navigator as a master-detail form on a page, only its immediate parent master object displays on the page. The hierarchy will not display all the way up to the topmost parent object.

If you display the detail object as a tree or tree table object, it is possible to display the entire hierarchy with multiple levels of depth, starting with the topmost master object, and traversing detail children objects at each node.

6.2 Identifying Master-Detail Objects on the Data Controls Panel

You can declaratively create pages that display master-detail data using the Data Controls panel. The Data Controls panel displays master-detail related objects in a hierarchy that mirrors the data model where the detail objects are children of the master objects.

To display master-detail objects as form or table objects, drag the detail object from the Data Controls panel and drop it on the page. Its master object is automatically created on the page.

Figure 6-2 shows two master-detail related accessor returned collections in the Data Controls panel. ProductImageList appears as a child of ProductFindAll.

Note:

The master-detail hierarchy displayed in the Data Controls panel does not reflect the cardinality of the relationship (that is, one-to-many, one-to-one, many-to-many). The hierarchy simply shows which accessor returned collection (the master) is being used to retrieve one or more objects from another accessor returned collection (the detail).

Figure 6-2 Master-Detail Objects in the Data Controls Panel

Master-detail objects in the Data Controls panel.

In this example, the relationship between ProductFindAll and ProductImageList is a one-way relationship.

6.3 Using Tables and Forms to Display Master-Detail Objects

You can create a master-detail browse page in a single declarative action using the Data Controls panel. All you have to do is drop the detail accessor returned collection on the page and choose the type of widget you want to use.

The prebuilt master-detail widgets available from the Data Controls panel include range navigation that enables the end user to scroll through the data objects in collections. You can delete unwanted attributes by removing the text field or column from the page.

Figure 6-3 shows an example of a prebuilt master-detail widget, which displays products information in a form at the top of the page and stock levels in a table at the bottom of the page. When the user clicks the Next button to scroll through the records in the master data at the top of the page, the page automatically displays the related detail data.

Figure 6-3 Prebuilt Data Controls Panel Master-Detail Widget

Prebuilt master-detail widget.

6.3.1 How to Display Master-Detail Objects in Tables and Forms

If you do not want to use the prebuilt master-detail widgets, you can drag and drop the master and detail objects individually from the Data Controls panel as tables and forms on a single page or on separate pages.

The Data Controls panel enables you to create both the master and detail widgets on one page with a single declarative action using prebuilt master-detail forms and tables.

To create a master-detail page using the prebuilt ADF master-detail forms and tables:

  1. From the Data Controls panel, locate the detail object.

  2. Drag and drop the detail object onto the JSF page.

    Note:

    If you want to create an editable master-detail form, drop the master object and the detail object separately on the page.
  3. In the context menu, choose one of the following master-details UI components:

    • ADF Master Table, Detail Form: Displays the master objects in a table and the detail objects in a read-only form under the table.

      When a specific data object is selected in the master table, the first related detail data object is displayed in the form below it. The user must use the form navigation to scroll through each subsequent detail data object.

    • ADF Master Form, Detail Table: Displays the master objects in a read-only form and the detail objects in a read-only table under the form.

      When a specific master data object is displayed in the form, the related detail data objects are displayed in a table below it.

    • ADF Master Form, Detail Form: Displays the master and detail objects in separate forms.

      When a specific master data object is displayed in the top form, the first related detail data object is displayed in the form below it. The user must use the form navigation to scroll through each subsequent detail data object.

    • ADF Master Table, Detail Table: Displays the master and detail objects in separate tables.

      When a specific master data object is selected in the top table, the first set of related detail data objects is displayed in the table below it.

6.3.2 What Happens When You Create Master-Detail Tables and Forms

When you drag and drop an accessor returned collection from the Data Controls panel, JDeveloper does many things for you, including adding code to the JSF page and the corresponding entries in the page definition file.

6.3.2.1 Code Generated in the JSF Page

The JSF code generated for a prebuilt master-detail widget is similar to the JSF code generated when you use the Data Controls panel to create a read-only form or table. If you are building your own master-detail widgets, you might want to consider including similar components that are automatically included in the prebuilt master-detail tables and forms.

The tables and forms in the prebuilt master-detail widgets include a panelHeader tag that contains the fully qualified name of the data object populating the form or table. You can change this label as needed using a string or an EL expression that binds to a resource bundle.

If there is more than one data object in a collection, a form in a prebuilt master-detail widget includes four commandButton tags for range navigation: First, Previous, Next, and Last. These range navigation buttons enable the user to scroll through the data objects in the collection. The actionListener attribute of each button is bound to a data control operation, which performs the navigation. The execute property used in the actionListener binding invokes the operation when the button is clicked. (If the form displays a single data object, JDeveloper automatically omits the range navigation components.)

Tip:

If you drop an ADF Master Table, Detail Form or ADF Master Table, Detail Table widget on the page, the parent tag of the detail component (for example, panelHeader tag or table tag) automatically has the partialTriggers attribute set to the id of the master component. At runtime, the partialTriggers attribute causes only the detail component to be rerendered when the user makes a selection in the master component, which is called partial rendering. When the master component is a table, ADF uses partial rendering, because the table does not need to be rerendered when the user simply makes a selection in the facet. Only the detail component needs to be rerendered to display the new data.

6.3.2.2 Binding Objects Defined in the Page Definition File

Example 6-1 shows the page definition file created for a master-detail page that was created by dropping WarehouseStockLevelList, which is a detail object under the ProductFindAll object, on the page as an ADF Master Form, Detail Table.

The executables element defines two accessorIterators: one for the product (the master object) and one for WarehouseStockLevels (the detail object). At runtime, the UI-aware data model and the row set iterator keep the row set of the detail collection refreshed to the correct set of rows for the current master row as that current row changes.

The bindings element defines the value bindings. The attribute bindings that populate the text fields in the form are defined in the attributeValues elements. The id attribute of the attributeValues element contains the name of each data attribute, and the IterBinding attribute references an iterator binding to display data from the master object in the text fields.

The attribute bindings that populate the text fields in the form are defined in the attributeValues elements. The id attribute of the attributeValues element contains the name of each data attribute, and the IterBinding attribute references an iterator binding to display data from the master object in the text fields.

The range navigation buttons in the form are bound to the action bindings defined in the action elements. As in the attribute bindings, the IterBinding attribute of the action binding references the iterator binding for the master object.

The table, which displays the detail data, is bound to the table binding object defined in the table element. The IterBinding attribute references the iterator binding for the detail object.

Example 6-1 Binding Objects Defined in the Page Definition for a Master-Detail Page

<executables>
    <variableIterator id="variables"/>
    <iterator Binds="root" RangeSize="25" DataControl="SupplierFacadeLocal"
              id="SupplierFacadeLocalIterator"/>
    <accessorIterator MasterBinding="SupplierFacadeLocalIterator"
                      Binds="productFindAll" RangeSize="25"
                      DataControl="SupplierFacadeLocal"
                      BeanClass="oracle.fodemo.supplier.model.Product"
                      id="productFindAllIterator"
                      ChangeEventPolicy="ppr"/>
    <accessorIterator MasterBinding="productFindAllIterator"
                      Binds="warehouseStockLevelList" RangeSize="25"
                      DataControl="SupplierFacadeLocal"
                      BeanClass="oracle.fodemo.supplier.model.WarehouseStockLevel"
                      id="warehouseStockLevelListIterator"
                      ChangeEventPolicy="ppr"/>
  </executables>
  <bindings>
   <action IterBinding="productFindAllIterator" id="First"
            RequiresUpdateModel="true" Action="first"/>
   <action IterBinding="productFindAllIterator" id="Previous"
            RequiresUpdateModel="true" Action="previous"/>
   ...
    <attributeValues IterBinding="productFindAllIterator" id="attribute1">
      <AttrNames>
        <Item Value="warrantyPeriodMonths"/>
      </AttrNames>
    </attributeValues>
    ...
    <tree IterBinding="warehouseStockLevelListIterator"
          id="warehouseStockLevelList">
      <nodeDefinition DefName="oracle.fodemo.supplier.model.WarehouseStockLevel">
        <AttrNames>
          <Item Value="lastUpdateDate"/>
          <Item Value="objectVersionId"/>
          <Item Value="productId"/>
          <Item Value="quantityOnHand"/>
          ...
          <Item Value="warehouseId"/>
        </AttrNames>
      </nodeDefinition>
    </tree>
  </bindings>

6.3.3 What Happens at Runtime: ADF Iterator for Master-Detail Tables and Forms

At runtime, an ADF iterator determines which row from the master table object to display in the master-detail form. When the form first displays, the first master table object row appears highlighted in the master section of the form. Detail table rows that are associated with the master row display in the detail section of the form.

As described in Section 6.3.2.2, "Binding Objects Defined in the Page Definition File," ADF iterators are associated with underlying rowsetIterator objects. These iterators manage which data objects, or rows, currently display on a page. At runtime, the row set iterators manage the data displayed in the master and detail components.

Both the master and detail row set iterators listen to row set navigation events, such as the user clicking the range navigation buttons, and display the appropriate row in the UI. In the case of the default master-detail components, the row set navigation events are the command buttons on a form (First, Previous, Next, Last).

The row set iterator for the detail collection manages the synchronization of the detail data with the master data. The detail row set iterator listens for row navigation events in both the master and detail collections. If a row set navigation event occurs in the master collection, the detail row set iterator automatically executes and returns the detail rows related to the current master row.

6.3.4 What You May Need to Know About Displaying Master-Detail Widgets on Separate Pages

The default master-detail components display the master-detail data on a single page. However, using the master and detail objects on the Data Controls panel, you can also display the collections on separate pages, and still have the binding iterators manage the synchronization of the master and detail objects.

To display master-detail objects on separate pages, create two pages, one for the master object and one for the detail object, using the individual tables or forms available from the Data Controls panel. Remember that the detail object iterator manages the synchronization of the master and detail data. Be sure to drag the appropriate detail object from the Data Controls panel when you create the page to display the detail data. For more information, see Section 6.2, "Identifying Master-Detail Objects on the Data Controls Panel."

To handle the page navigation, create an ADF task flow, and then add two view activities to it, one for the master page and one for the detail page. Add command buttons or links to each page, or use the default Submit button available when you create a form or table using the Data Controls panel. Each button must specify a navigation rule outcome value in the action attribute. In the task-flow-defintion.xml file, add a navigation rule from the master data page to the detail data page, and another rule to return from the detail data page to the master data page. The from-outcome value in the navigation rules must match the outcome value specified in the action attribute of the buttons.

6.4 Using Trees to Display Master-Detail Objects

In addition to tables and forms, you can also display master-detail data in hierarchical trees. The ADF Faces tree component is used to display hierarchical data. It can display multiple root nodes that are populated by a binding on a master object. Each root node in the tree may have any number of branches, which are populated by bindings on detail objects. A tree can have multiple levels of nodes, each representing a detail object of the parent node. Each node in the tree is indented to show its level in the hierarchy.

The tree component includes mechanisms for expanding and collapsing the tree nodes; however, it does not have focusing capability. If you need to use focusing, consider using the ADF Faces treeTable component (for more information, see Section 6.5, "Using Tree Tables to Display Master-Detail Objects"). By default, the icon for each node in the tree is a folder; however, you can use your own icons for each level of nodes in the hierarchy.

Figure 6-4 shows an example of a tree that displays two levels of nodes: root and branch. The root node displays parent product categories such as Media, Office, and Electronics. The branch nodes display and subcategories under each parent category, such as Hardware, Supplies, and Software under the Office parent category.

Figure 6-4 Databound ADF Faces Tree

This shows a databound ADF Faces tree.

6.4.1 How to Display Master-Detail Objects in Trees

A tree consists of a hierarchy of nodes, where each subnode is a branch off a higher level node. Each node level in a databound ADF Faces tree component is populated by a different data collection. In JDeveloper, you define a databound tree using the Edit Tree Binding dialog, which enables you to define the rules for populating each node level in the tree. There must be one rule for each node level in the hierarchy. Each rule defines the following node-level properties:

  • The accessor returned collection that populates that node level

  • The attributes from the accessor returned collection that are displayed at that node level

To display master-detail objects in a tree:

  1. Drag the master object from the Data Controls panel, and drop it onto the page. This should be the master data that will represent the root level of the tree.

  2. In the context menu, choose Trees > ADF Tree.

    JDeveloper displays the Edit Tree Binding dialog, as shown in Figure 6-5. You use the binding editor to define a rule for each level that you want to appear in the tree.

    Figure 6-5 Edit Tree Binding Dialog

    Shows the Edit Tree Binding dialog.
  3. In the Root Data Source dropdown list, select the accessor returned collection that will populate the root node level.

    This will be the master data collection. By default, this is the same collection that you dragged from the Data Controls panel to create the tree, which was a master collection.

    Tip:

    If you don't see the accessor returned collection you want in the Root Data Source list, click the Add button. In the Add Data Source dialog, select a data control and an iterator name to create a new data source.
  4. Click the Add icon to add the root data source you selected to the Tree Level Rules list.

  5. In the Tree Level Rules list, select the data source you just added.

  6. Select an attribute in the Available Attributes list and move it to the Display Attributes list.

    The attribute will be used to display nodes at the master level.

    After defining a rule for the master level, you must next define a second rule for the detail level that will appear under the master level in the tree.

  7. To add a second rule, click the Add icon above the Tree Level Rules list.

    A detail data source should appear automatically under the master data source, as shown in Figure 6-6.

    Figure 6-6 Master-Detail Tree Level Rules

    Shows master-detail tree rules.

    For example, if you specified ProductFindAll as the master root data source, WarehouseStockLevelList will automatically appear underneath in the Tree Level Rules list, because the two data sources share a master-detail relationship.

    If you are creating a tree with a recursive master-detail hierarchy, then you only need to define a rule that specifies a data source with a self-accessor. A recursive tree displays root nodes based on a single collection and displays the child nodes from the attributes of a self-accessor that recursively fetches data from that collection. The recursive tree differs from a typical master-detail tree because it requires only a single rule to define the branches of the tree. A recursive data source should display the data source followed by the name of the self-accessor in brackets, as shown in Figure 6-7.

    Figure 6-7 Recursive Tree-Level Rule

    Shows a recursive tree rule.

    For example, in a collection defined by EmployeesView, the root node of each branch could be specified by the ManagerId for the employee, and the child nodes of the same branch would then be the employees who are related to the ManagerId, as specified by the self-accessor DirectReports.

  8. Click OK.

  9. You can add data sources to the Tree Level Rules list to increase the number of nodes that display in the tree. The order of the remaining data sources should follow the hierarchy of the nodes you want to display in the tree.

6.4.2 What Happens When You Create an ADF Databound Tree

When you drag and drop from the Data Controls panel, JDeveloper does many things for you.

When you create a databound tree using the Data Controls panel, JDeveloper adds binding objects to the page definition file, and it also adds the tree tag to the JSF page. The resulting UI component is fully functional and does not require any further modification.

6.4.2.1 Code Generated in the JSF Page

Example 6-2 shows the code generated in a JSF page when you use the Data Controls panel to create a tree. This sample tree displays the order numbers as the root nodes and the product names as the leaf nodes.

Example 6-2 Code Generated in the JSF Page for a Databound Tree

<af:tree 
   value="#{bindings.orderItemFindAll.treeModel}" 
   var="node"
   selectionListener="#{bindings.orderItemFindAll.treeModel.makeCurrent}"
   rowSelection="single" id="orderItemsTree">
   <f:facet name="nodeStamp">
       <af:outputText value="#{node}" id="ot2"/>
   </f:facet>
</af:tree>

By default, the af:tree tag is created inside a form. The value attribute of the tree tag contains an EL expression that binds the tree component to the orderItemFindAll tree binding object in the page definition file. The treeModel property in the binding expression refers to an ADF class that defines how the tree hierarchy is displayed, based on the underlying data model. The var attribute provides access to the current node.

In the f:facet tag, the nodeStamp facet is used to display the data for each node. Instead of having a component for each node, the tree repeatedly renders the nodeStamp facet, similar to the way rows are rendered for the ADF Faces table component.

The ADF Faces tree component uses an instance of the oracle.adf.view.faces.model.PathSet class to display expanded nodes. This instance is stored as the treeState attribute on the component. You may use this instance to programmatically control the expanded or collapsed state of an element in the hierarchy. Any element contained by the PathSet instance is deemed expanded. All other elements are collapsed.

6.4.2.2 Binding Objects Defined in the Page Definition File

Example 6-3 shows the binding objects defined in the page definition file for the ADF databound tree.

Example 6-3 Binding Objects Defined in the Page Definition File for a Databound Tree

<executables>
    <variableIterator id="variables"/>
    <iterator Binds="root" RangeSize="25" DataControl="SupplierFacadeLocal"
              id="SupplierFacadeLocalIterator"/>
    <accessorIterator MasterBinding="SupplierFacadeLocalIterator"
                      Binds="orderItemFindAll" RangeSize="25"
                      DataControl="SupplierFacadeLocal"
                      BeanClass="oracle.fodemo.supplier.model.OrderItem"
                      id="orderItemFindAllIterator"/>
</executables>
<bindings>
    <tree IterBinding="orderItemFindAllIterator" id="orderItemFindAll">
      <nodeDefinition DefName="oracle.fodemo.supplier.model.OrderItem"
                      Name="orderItemFindAll0">
        <AttrNames>
          <Item Value="orderId"/>
        </AttrNames>
        <Accessors>
          <Item Value="product"/>
        </Accessors>
      </nodeDefinition>
      <nodeDefinition DefName="oracle.fodemo.supplier.model.Product"
                      Name="orderItemFindAll1">
        <AttrNames>
          <Item Value="productName"/>
        </AttrNames>
      </nodeDefinition>
    </tree>
</bindings>

The tree element is the value binding for all the attributes displayed in the tree. The iterBinding attribute of the tree element references the iterator binding that populates the data in the tree. The AttrNames element within the tree element defines binding objects for all the attributes in the master collection. However, the attributes that you select to appear in the tree are defined in the AttrNames elements within the nodeDefinition elements.

The nodeDefinition elements define the rules for populating the nodes of the tree. There is one nodeDefinition element for each node, and each one contains the following attributes and subelements:

  • DefName: An attribute that contains the fully qualified name of the data collection that will be used to populate the node

  • id: An attribute that defines the name of the node

  • AttrNames: A subelement that defines the attributes that will be displayed in the node at runtime

  • Accessors: A subelement that defines the accessor attribute that returns the next branch of the tree

The order of the nodeDefintion elements within the page definition file defines the order or level of the nodes in the tree, where the first nodeDefinition element defines the root node. Each subsequent nodeDefinition element defines a subnode of the one before it.

6.4.3 What Happens at Runtime: Displaying an ADF Databound Tree

Tree components use org.apache.myfaces.trinidad.model.TreeModel to access data. This class extends CollectionModel, which is used by the ADF Faces table component to access data. For more information about the TreeModel class, refer to the ADF Faces Javadoc.

When a page with a tree is displayed, the iterator binding on the tree populates the root nodes. When a user expands or collapses a node to display or hide its branches, a DisclosureEvent event is sent. The isExpanded method on this event determines whether the user is expanding or collapsing the node. The DisclosureEvent event has an associated listener.

The DisclosureListener attribute on the tree is bound to the accessor attribute specified in the node rule defined in the page definition file. This accessor attribute is invoked in response to the DisclosureEvent event; in other words, whenever a user expands the node the accessor attribute populates the branch nodes.

6.5 Using Tree Tables to Display Master-Detail Objects

Use the ADF Faces treeTable component to display a hierarchy of master-detail collections in a table. The advantage of using a treeTable component rather than a tree component is that the treeTable component provides a mechanism that enables users to focus the view on a particular node in the tree.

For example, you can create a tree table that displays three levels of nodes: countries, states or provinces, and cities. Each root node represents an individual country. The branches off the root nodes display the state or provinces in the country. Each state or province node branches to display the cities contained in it.

As with trees, to create a tree table with multiple nodes, it is necessary to have master-detail relationships between the collections. For example, to create a tree table with three levels of country, state, and city, it was necessary to have a master-detail relationship from the CountryCodes collection to the StatesandProvinces collection, and a master-detail relationship from the StatesandProvinces collection to the Cities collection.

A databound ADF Faces treeTable displays one root node at a time, but provides navigation for scrolling through the different root nodes. Each root node can display any number of branch nodes. Every node is displayed in a separate row of the table, and each row provides a focusing mechanism in the leftmost column.

You can edit the following treeTable component properties in the Property Inspector:

6.5.1 How to Display Master-Detail Objects in Tree Tables

The steps for creating an ADF Faces databound tree table are exactly the same as those for creating an ADF Faces databound tree, except that you drop the accessor returned collection as an ADF Tree Table instead of an ADF Tree.

6.5.2 What Happens When You Create a Databound Tree Table

When you drag and drop from the Data Controls panel, JDeveloper does many things for you.

When you create a databound tree table using the Data Controls panel, JDeveloper adds binding objects to the page definition file, and it also adds the treeTable tag to the JSF page. The resulting UI component is fully functional and does not require any further modification.

6.5.2.1 Code Generated in the JSF Page

Example 6-4 shows the code generated in a JSF page when you use the Data Controls panel to create a tree table. This sample tree table displays two levels of nodes: products and stock levels.

By default, the treeTable tag is created inside a form. The value attribute of the tree table tag contains an EL expression that binds the tree component to the binding object that will populate it with data. The treeModel property refers to an ADF class that defines how the tree hierarchy is displayed, based on the underlying data model. The var attribute provides access to the current node.

Example 6-4 Code Generated in the JSF Page for a Databound ADF Faces Tree Table

<af:treeTable value="#{bindings.orderItemFindAll.treeModel}" var="node"
     selectionListener="#{bindings.orderItemFindAll.treeModel.makeCurrent}"
     rowSelection="single" id="tt1">
     <f:facet name="nodeStamp">
          <af:column id="c1">
              <af:outputText value="#{node}" id="ot1"/>
          </af:column>
     </f:facet>
     <f:facet name="pathStamp">
          <af:outputText value="#{node}" id="ot2"/>
     </f:facet>
</af:treeTable>

In the facet tag, the nodeStamp facet is used to display the data for each node. Instead of having a component for each node, the tree repeatedly renders the nodeStamp facet, similar to the way rows are rendered for the ADF Faces table component. The pathStamp facet renders the column and the path links above the table that enable the user to return to the parent node after focusing on a detail node.

6.5.2.2 Binding Objects Defined in the Page Definition File

The binding objects created in the page definition file for a tree table are exactly the same as those created for a tree.

6.5.3 What Happens at Runtime: Events

Tree components use oracle.adf.view.faces.model.TreeModel to access data. This class extends CollectionModel, which is used by the ADF Faces table component to access data. For more information about the TreeModel class, refer to the ADF Faces Javadoc.

When a page with a tree table is displayed, the iterator binding on the treeTable component populates the root node and listens for a row navigation event (such as the user clicking the Next or Previous buttons or selecting a row from the range navigator). When the user initiates a row navigation event, the iterator displays the appropriate row.

If the user changes the view focus (by clicking on the component's focus icon), the treeTable component generates a focus event (FocusEvent). The node to which the user wants to change focus is made the current node before the event is delivered. The treeTable component then modifies the focusPath property accordingly. You can bind the FocusListener attribute on the tree to a method on a managed bean. This method will then be invoked in response to the focus event.

When a user expands or collapses a node, a disclosure event (DisclosureEvent) is sent. The isExpanded method on the disclosure event determines whether the user is expanding or collapsing the node. The disclosure event has an associated listener, DisclosureListener. The DisclosureListener attribute on the tree table is bound to the accessor attribute specified in the node rule defined in the page definition file. This accessor attribute is invoked in response to a disclosure event (for example, the user expands a node) and returns the collection that populates that node.

The treeTable component includes Expand All and Collapse All links. When a user clicks one of these links, the treeTable sends a DisclosureAllEvent event. The isExpandAll method on this event determines whether the user is expanding or collapsing all the nodes. The table then expands or collapses the nodes that are children of the root node currently in focus. In large trees, the expand all command will not expand nodes beyond the immediate children. The ADF Faces treeTable component uses an instance of the oracle.adf.view.faces.model.PathSet class to determine expanded nodes. This instance is stored as the treeState attribute on the component. You can use this instance to programmatically control the expanded or collapsed state of a node in the hierarchy. Any node contained by the PathSet instance is deemed expanded. All other nodes are collapsed. This class also supports operations like addAll() and removeAll().

Like the ADF Faces table component, a treeTable component provides for range navigation. However, instead of using the rows attribute, the treeTable component uses a rowsByDepth attribute whose value is a space-separated list of non-negative numbers. Each number defines the range size for a node level on the tree. The first number is the root node of the tree, and the last number is for the branch nodes. If there are more branches in the tree than numbers in the rowsByDepth attribute, the tree uses the last number in the list for the remaining branches. Each number defines the limit on the number items displayed at one time in each branch. If you want to display all items in a branch, specify 0 in that position of the list.

For example, if the rowsByDepth attribute is set to 0 0 3, all root nodes will be displayed, all direct children of the root nodes will be displayed, but only three nodes will display per branch after that. The treeTable component includes links to navigate to additional nodes, enabling the user to display the additional nodes.

For more information about the ADF Faces treeTable component, refer to the oracle.adf.view.faces.component.core.data.CoreTreeTable class in the ADF Faces Javadoc.

6.5.4 Using the TargetIterator Property

You can expand a node binding in the page definition editor to view the page's node Definition elements. These are the same tree binding rules that you can configure in the tree binding dialog.

For each node definition (rule), you can specify an optional TargetIterator property. Its value is an EL expression that is evaluated at runtime when the user selects a row in the tree. The EL expression evaluates an iterator binding in the current binding container. The iterator binding's row key attributes match (in order, number, and data type) the row key of the iterator from which the nodeDefinition type's rows are retrieved for the tree.

At runtime, when the tree control receives a selectionChanged event, it passes in the list of keys for each level of the tree. These keys uniquely identify the selected node.

The tree binding starts at the top of the tree. For each tree level whose key is present in the Currently Selected Tree Node Keys list, if there is a TargetIterator property configured for that nodeDefinition, the tree binding performs a setCurrentRowWithKey() operation on the selected target iterator. It uses the key from the appropriate level of the Currently Selected Tree Node Keys list.

6.6 Using Selection Events with Trees and Tables

There may be cases when you need to determine which node in a tree or tree table has been selected in order to handle some processing in your application. For example, when a user selects a category node in a Browse tree, a selection event is fired. The listener associated with this event needs to determine the product category of the node selected, and then to return all products whose category attribute matches that value.

6.6.1 How to Use Selection Events with Trees and Tables

To programmatically use selection events, you need to create a listener in a managed bean that will handle the selection event and perform the needed logic. You then need to bind the selectionListener attribute of the tree or table to that listener.

To use selection events with trees and tables:

  1. If one does not already exist, create a managed bean to contain the needed listener.

  2. Create a listener method on the managed bean. For more information about creating listener methods, see the "Using ADF Faces Server Events" section of the Oracle Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework. Your listener should do the following:

    1. Access the component using the event source. Example 6-5 shows how the productCategoriesTreeSelectionListener method on the HomeBean managed bean accesses the tree that launched the selection event.

      Example 6-5 Getting the Source of an Event

      public void productCategoriesTreeSelectionListener(SelectionEvent evt) {
          RichTree tree = (RichTree)evt.getSource();
      

      For more information about finding the event source component, see the "How to Return the Original Source of the Event" section of the Oracle Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework.

    2. Access the tree model to get the value of the model, use the RowKeySet object to get the currently selected node, and then set that as the current row on the model, as shown in Example 6-6. For more information about RowKeySet objects, see Section 6.6.2, "What Happens at Runtime: RowKeySet Objects and SelectionEvent Events."

      Example 6-6 Setting the Current Row on a Tree Model

      TreeModel model = (TreeModel)tree.getValue();
      RowKeySet rowKeySet = evt.getAddedSet();
      Object key = rowKeySet.iterator().next();
      model.setRowKey(key);
      
    3. You can now add logic to execute against the currently selected row. For example, the productCategoriesTreeSelectionListener method uses the value binding of the selected row to determine the category ID, and then uses that value as the parameter for another method that, when executed, returns all products with that category ID, as shown in Example 6-7.

      Example 6-7 Returning Objects That Match a Given Attribute Value

      JUCtrlValueBinding nodeBinding = 
          (JUCtrlValueBinding)model.getRowData();
      Number catId = (Number)nodeBinding.getAttribute("CategoryId");
      _selectedCategory = (String)nodeBinding.getAttribute("CategoryName");
      
      OperationBinding ob =
           ADFUtils.findOperation("ProductsByCategoriesExecuteWithParams");
      ob.getParamsMap().put("category", catId);
      ob.execute();
      
  3. On the associated JSF page, select the tree or table component. In the Property Inspector, expand the Behavior section and set the value of the SelectionListener attribute to the listener method just created. You can use the Edit option from the dropdown method to declaratively select the bean and the method.

6.6.2 What Happens at Runtime: RowKeySet Objects and SelectionEvent Events

Whenever a user selects a node in a tree (or a row in a table), the component triggers selection events. A selectionEvent event reports which rows were just deselected and which rows were just selected. The current selection, that is, the selected row or rows, is managed by the RowKeySet object, which keeps track of all currently selected nodes by adding and deleting the associated key for the row into or out of the key set. When a user selects a new node, and the tree or table is configured for single selection, then the previously selected key is discarded and the newly selected key is added. If the tree or table is configured for multiple selection, then the newly selected keys are added to the set, and the previously selected keys may or may not be discarded, based on how the nodes were selected. For example, if the user pressed the CTRL key, then the newly selected nodes would be added to the current set.