24 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 25, "Creating Databound Selection Lists and Shuttles".

24.1 Introduction to Displaying Master-Detail Data

In ADF Business Components, a master-detail relationship refers to two view object instances that are related by a view link. As described in Section 5.1, "Introduction to View Objects", a view link represents the relationship between two view objects, which is usually, but not necessarily, based on a foreign-key relationship between the underlying data tables. The view link associates a row of one view object instance (the master object) with one or more rows of another view object instance (the detail object).

To display master-detail data on a page using ADF data binding, you exclusively use data model view link instances, which support master-detail coordination. When using ADF Business Components in combination with the ADF Model layer and ADF Faces UI components, the data model automatically updates to reflect any changes to the row sets of these business objects.

To enable master-detail coordination, you must add both the master view object and the detail view object instances to the application module data model. For example, in the Fusion Order Demo application, there is a view link from the ProductsVO view object to the WarehouseStockLevelsVO view object based on the ProductId attribute, both contained in the application module data model, as shown in Figure 24-1. A change in the current row of the master view object instance causes the row set of the detail view object instance to refresh to include the details for the current master.

Figure 24-1 View Link between Products and WarehouseStockLevels View Objects

This shows the Create View Link dialog.

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 24-2 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 24-2 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.

24.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 one you defined in the application module data model, where the detail objects are children of the master objects. For information about adding master-detail objects to the data model, see Section 5.6.4, "How to Enable Active Master-Detail Coordination in the Data Model."

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 24-3 shows two master-detail related collections in the Data Controls panel of the Fusion Order Demo application. The Products collection is an instance of the ProductsVO view object, and the WarehouseStockLevels collection, which appears as a child of the Products collection, is an instance of the WarehouseStockLevelsVO view object.

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 collection (the master) is being use to retrieve one or more objects from another collection (the detail).

Figure 24-3 Master-Detail Objects in the Data Controls Panel

Master-detail objects in the Data Controls panel.

The master-detail hierarchy on the Data Controls panel reflects the hierarchy defined in the application module data model, as shown in Figure 24-4. The hierarchy was established by creating a view link from the ProductsVO view object to the WarehouseStockLevelsVO view object. Next, an instance of the resulting detail view object, WarehouseStockLevelsVO via ProductsToWarehouseStockLevels, was added to the application module data model shown in Figure 24-4.

Figure 24-4 Master-Detail Hierarchy Defined in the Application Module Data Model

This shows a master-detail hierarchy.

In the Fusion Order Demo application, the view link between the ProductsVO view object and WarehouseStockLevelsVO view object is a one-way relationship. If the view link were bidirectional and both sets of master and detail view objects were added to the application module data model, then the Data Controls panel would also display the WarehouseStockLevelsVO collection at the same node level as the Products collection, and the detail instance of the Products collection as a child of the WarehouseStockLevelsVO collection.

Tip:

By default, when you define a view link using the Create View Link wizard, the source view object is the master and the destination view object is the detail. However, if you choose to generate accessors in both the source and the destination view objects, then the master-detail relationship is bidirectional. If both sets of master-detail view objects resulting from a bidirectional view link are added to the application module data model, then instances of both sets of view objects will appear independently on the Data Controls panel.

For more information about the icons displayed on the Data Controls panel, see "Section 12.3.1, "How to Use the Data Controls Panel."

24.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 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 24-5 shows an example of 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 24-5 Prebuilt Data Controls Panel Master-Detail Widget

Default master-detail widget

24.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. For information about displaying master and detail data on separate pages, see Section 24.3.4, "What You May Need to Know About Displaying Master-Detail Widgets on Separate Pages."

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, as described in Section 24.2, "Identifying Master-Detail Objects on the Data Controls Panel."

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

    If you want to modify the default forms or tables, see Section 22.3, "Creating a Basic Form" or Section 23.2, "Creating a Basic Table."

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

When you drag and drop a 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. For a full description of what happens and what is created when you use the Data Controls panel, see Section 12.3.1, "How to Use the Data Controls Panel."

24.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.) For more information about range navigation, see Section 22.4, "Incorporating Range Navigation into Forms."

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 (see Section 23.4.1, "How to Create an Input Table" for more information about partial triggers). 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.

24.3.2.2 Binding Objects Defined in the Page Definition File

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

The executables element defines two iterators: one for the product (the master object) and one for the WarehouseStockLevels (the detail object). The underlying view link from the master view object to the detail view object establishes the relationship between the two iterators. At runtime, the UI-aware data model and the row set iterator for the detail view object instance keep the row set of the detail view object refreshed to the correct set of rows for the current master row as that current row changes (for more information, see Section 24.3.3, "What Happens at Runtime: ADF Iterator for Master-Detail Tables and Forms").

The bindings element defines the value bindings for the form and the table. 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.

For more information about the elements and attributes of the page definition file, see Section A.8, "pageNamePageDef.xml."

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

<executables>
    <iterator Binds="Products" RangeSize="25"
              DataControl="StoreServiceAMDataControl" id="ProductsIterator"/>
    <iterator Binds="WarehouseStockLevels" RangeSize="25"
              DataControl="StoreServiceAMDataControl"
              id="WarehouseStockLevelsIterator"/>
</executables>

<bindings>
    <methodAction id="findHelpTextById" RequiresUpdateModel="true"
                  Action="invokeMethod" MethodName="findHelpTextById"
                  IsViewObjectMethod="false"
                  DataControl="LookupServiceAMDataControl"
                  InstanceName="LookupServiceAMDataControl.dataProvider"
                  ReturnName="LookupServiceAMDataControl.methodResults.
                      findHelpTextById_LookupServiceAMDataControl_
                      dataProvider_findHelpTextById_result">
                  <NamedData NDName="helpId" NDType="java.lang.Long"
                       NDOption="2"/>
    </methodAction>
    <tree IterBinding="ProductsIterator" id="Products">
      <nodeDefinition DefName="oracle.fodemo.storefront.store.queries.ProductsVO">
        <AttrNames>
          <Item Value="ProductId"/>
          <Item Value="SupplierId"/>
          <Item Value="CategoryId"/>
          <Item Value="ProductName"/>
          ...   
          <Item Value="CostPrice"/>
          <Item Value="DragId"/>
        </AttrNames>
      </nodeDefinition>
    </tree>
    <tree IterBinding="WarehouseStockLevelsIterator" id="WarehouseStockLevels">
      <nodeDefinition DefName="oracle.fodemo.storefront.store.
           queries.WarehouseStockLevelsVO">
        <AttrNames>
          <Item Value="ProductId"/>
          <Item Value="WarehouseId"/>
          ...
          <Item Value="ShippingClassCode"/>
        </AttrNames>
      </nodeDefinition>
    </tree>
</bindings>

24.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 24.3.2.2, "Binding Objects Defined in the Page Definition File," ADF iterators are associated with underlying row setIterator 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. Because of the underlying view link from the master view object to the detail view object, 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.

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

For example, in the Fusion Order Demo application, a product table and product details are displayed on the home page. However, the page could display the product table only. It could provide a button called Details. If the user clicked the Details button, the application would navigate to a new page that displays all the related details in a list. A button on the list's page would enable the user to return to the service request page.

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 24.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. (See Section 14.2, "Creating a Task Flow" for information about associating a View activity with an existing JSF 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. For information about adding navigation between pages, see Section 14.2, "Creating a Task Flow."

24.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 24.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 24-6 shows an example of a tree located on the home.jspx page of the Fusion Order Demo application. The tree 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 24-6 Databound ADF Faces Tree

This shows a databound ADF Faces tree.

24.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:

To create the Browse tree on the Fusion Order Demo home page shown in Figure 24-6, a view object, ParentProductCategories was created to return a list of parent categories. Another view object, ProductCategories was created to return subcategories of products. A view link was created from the ParentProductCategories view object to the ProductCategories view object, thus establishing a master-detail relationship.

To add a third-level node, for example, a list of products under each subcategory, a view link would need to exist from the ProductCategories object to the Products view object. For more information about creating view links, see Section 5.6.6, "How to Access the Detail Collection Using the View Link Accessor."

In the case where a branch of the tree is recursive, a single view object accompanied by a self-referential view link must be defined in the data model project. For example, in a collection defined by EmployeesView, the root node of each branch is specified by the ManagerId attribute and the child nodes of the same branch are the employees (also known as "direct reports") who are related to the ManagerId. The source and destination view object named by the self-referential view link are both defined as EmployeesView with the destination renamed to DirectReports for clarify. For more information about creating self-referential view links, see Section 5.7.1, "How to Create a Recursive Master-Detail Hierarchy for an Entity-Based View Object."

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 24-7. You use the binding editor to define a rule for each level that you want to appear in the tree.

    Figure 24-7 Edit Tree Binding Dialog

    Shows the Edit Tree Binding dialog.
  3. In the Root Data Source dropdown list, select the data 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 data 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 + 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. In the Accessor dropdown list, select a view link accessor attribute.

    The list displays only the accessor attributes that return the detail collections for the master collection you selected. For example, if you are defining the ParentProductCategories node level and you want to add a detail level that displays all subcategories under each parent category, you would select the accessor attribute that returns the ProductCategories collection.

    If you select <none>, the node will not expand to display any detail collections, thus ending the branch.

    View link accessor attributes, which return data collections, are generated when you create a view link. The Accessor field displays all accessor attributes that return detail collections for the master collection selected in the Tree Level Rules list. For more information about view objects, view links, and view link accessors, see Section 5.6.6, "How to Access the Detail Collection Using the View Link Accessor."

  7. 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. For example, for the Parent Product Categories level, you might select the Categories attribute.

    When you are finished, the Tree Binding Editor should contain values similar to those in Figure 24-7.

    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.

    For example, in the sample tree shown in Figure 24-6, the first rule added to the tree binding editor populates the parent category nodes (Media, Office, and Electronics). The detail level rule populates the product category nodes (for example, Hardware, Supplies, and Software under the Media parent category). '

  8. 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 24-8.

    Figure 24-8 Master-Detail Tree Level Rules

    Shows master-detail tree rules.

    For example, if you specified Products as the master Root Data Source, WarehouseStockLevels 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 24-9.

    Figure 24-9 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 are the employees who are related to the ManagerId, as specified by the self accessor DirectReports.

  9. Click OK.

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

24.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. For a full description of what happens and what is created when you use the Data Controls panel, see Section 12.3.1, "How to Use the Data Controls Panel."

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.

24.4.2.1 Code Generated in the JSF Page

Example 24-2 shows the code generated in a JSF page when you use the Data Controls panel to create a tree. This sample tree displays two levels of nodes: parent product categories and product categories. The ParentProductCategories collection was used to populate the root node.

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

<af:tree id="productCategoriesTree" contentDelivery="immediate"
            selectionListener="#{homePageBean.
                   productCategoriesTreeSelectionListener}"
            rowSelection="single"
            value="#{bindings.ParentProductCategories.treeModel}"
            var="node" initiallyExpanded="true">
       <f:facet name="nodeStamp">
             <af:panelGroupLayout>
                   <af:outputText rendered="#{node.ParentCategoryId eq null}"
                         value="#{node.CategoryName}"
                            inlineStyle="color:#FF8000;font-weight:bold;"/>
                   <af:outputText rendered="#{node.ParentCategoryId ne null}"
                         value="#{node.CategoryName}"/>
             </af:panelGroupLayout>
       </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 ParentProductCategories 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.

24.4.2.2 Binding Objects Defined in the Page Definition File

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

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

<executables>
    <iterator Binds="ParentProductCategories" RangeSize="25"
              DataControl="StoreServiceAMDataControl"
              id="ParentProductCategoriesIterator"/>
</executables>
<bindings>
    <tree IterBinding="ParentProductCategoriesIterator"
          id="ParentProductCategories">
      <nodeDefinition
          DefName="oracle.fodemo.storefront.store.queries.ProductCategoriesVO">
        <AttrNames>
          <Item Value="CategoryId"/>
        </AttrNames>
        <Accessors>
          <Item Value="ProductCategoriesVO"/>
          <Item Value="ParentCategoryIdProductCategoriesVO"/>
        </Accessors>
      </nodeDefinition>    </tree>
</bindings>


The page definition file contains the rule information defined in the Tree Binding Editor. In the executables element, notice that although the tree displays two levels of nodes, only one iterator binding object is needed. This iterator iterates over the master collection, which populates the root nodes of the tree. The accessor you specified in the node rules returns the detail data for each branch node.

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, were the first nodeDefinition element defines the root node. Each subsequent nodeDefinition element defines a sub-node of the one before it.

For more information about the elements and attributes of the page definition file, see Appendix A, "pageNamePageDef.xml."

24.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 collapses or expands 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.

24.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 create view links between the view objects. The view links establish the master-detail relationships For example, to create a tree table with three levels of country, state, and city, it was necessary to create view links from the CountryCodes object to the StatesandProvinces view object, and another view link from the StatesandProvinces view object to the Cities view object. For more information about creating view links, see Section 5.6, "Working with Multiple Tables in a Master-Detail Hierarchy."

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:

  • Range navigation: The user can click the Previous and Next navigation buttons to scroll through the root nodes.

  • List navigation: The list navigation, which is located between the Previous and Next buttons, enables the user to navigate to a specific root node in the data collection using a selection list.

  • Node expanding and collapsing mechanism: The user can open or close each node individually or use the Expand All or Collapse All command links. By default, the icon for opening and closing the individual nodes is an arrowhead with a plus or minus sign. You can also use a custom icon of your choosing.

  • Focusing mechanism: When the user clicks on the focusing icon (which is displayed in the leftmost column) next to a node, the page is redisplayed showing only that node and its branches. A navigation link is provided to enable the user to return to the parent node.

24.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 data collection as an ADF Tree Table instead of an ADF Tree.

24.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. For a full description of what happens and what is created when you use the Data Controls panel, see Section 12.3.1, "How to Use the Data Controls Panel."

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.

24.5.2.1 Code Generated in the JSF Page

Example 24-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 24-4 Code Generated in the JSF Page for a Databound ADF Faces Tree Table

<af:form>
      <af:treeTable value="#{bindings.Products.treeModel}" var="node"
                    selectionListener="#{bindings.Products.treeModel.makeCurrent}"
                    rowSelection="single">
        <f:facet name="nodeStamp">
          <af:column customizationId="column1">
            <af:outputText value="#{node}"/>
          </af:column>
        </f:facet>
        <f:facet name="pathStamp">
          <af:outputText value="#{node}"/>
        </f:facet>
      </af:treeTable>
</af:form>

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.

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

24.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 collapses or expands 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.

24.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 view row key attributes match (in order, number, and data type) the view 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.

For example, you may have created DeptEO and EmpEO entity objects, and created view links based on these entity objects. The view link accessor in the DeptVO object that returns the linked collection of employees in that department is named EmployeesInDepartment. The application module will have a DepartmentsTree view object instance of type DeptVO. It will also have an EditDepartment view object instance of type DeptVO, and a view link for the EditEmployees view object instance of type EmpVO.

To use the property:

  1. Drag the DepartmentsTree data collection from the Data Controls panel onto the page and choose Create > Trees > ADF Tree.

  2. Configure tree binding rules to navigate the EmployeesInDepartment view link accessor attribute.

    This will access the children employee rows of the current department row.

  3. Drag the EditEmployees detail view object instance to the page, and choose Create > Master-Detail > ADF Master Form, Detail Form.

    This creates a form to edit a department and a form to edit an employee in that department.

  4. For the DeptVO node definition of the tree binding, configure the TargetIterator property to be #{bindings.EditDepartmentIterator}.

  5. For the EmpVO node definition of the tree binding, configure the TargetIterator property to be #{bindings.EditEmployeesIterator}.

    When you run the master-detail form, clicking on an employee in any department in the tree will first set the current department row in the target iterator for the department of that selected employee. Then it will set the current employee row in the target iterator for the selected employee.

24.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, on the home page of the StoreFront module, when a user selects a category node in the 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.

24.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. For more information about creating and using managed beans, see Section 20.4, "Using a Managed Bean in a Fusion Web Application."

  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 24-5 shows how the productCategoriesTreeSelectionListener method on the HomeBean managed bean accesses the tree that launched the selection event.

      Example 24-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 24-6. For more information about RowKeySet objects, see Section 24.6.2, "What Happens at Runtime: RowKeySet Objects and SelectionEvent Events."

      Example 24-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 24-7.

      Example 24-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.

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