Skip Headers

Oracle® Application Development Framework Developer's Guide 10g Release 3 (10.1.3) B25386-01 |
| Home | Solution Area | Contents | Index

Previous | Next |

# 8.4 Using ADF Databound Trees to Display Master-Detail Relationships

In addition to displaying master-detail relationships in tables and forms, you can use the Data Control Palette to create databound trees using the ADF tree component.

The ADF tree component, `<af:tree>`, displays a hierarchy of master-detail related objects. A databound ADF Faces tree can display multiple root nodes that are populated by a binding on a master data collection. Each node in the tree may have any number of branches, which are populated by bindings on detail objects. Each node in the tree is indented to show its level in the hierarchy.

The ADF 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. 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 8-3 shows an example of a tree from the SRManage page of the SRDemo application. The tree displays two levels of nodes: users and service requests. The root nodes are users. The service requests associated with each user appear as a branch off each user node.

Figure 8-3 ADF Tree Component Created with ADF Databindings

## 8.4.1 How to Create a Databound Tree Using the Data Control Palette

A tree consists of a hierarchy of nodes, where each subnode is a branch off a higher level node. Each node level in an ADF tree is populated by a different data collection. In JDeveloper, you define a databound tree using the Tree Binding Editor, 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 data collection that populates the node level.

- The attributes from the data collection that are displayed at that node level

- An accessor method that returns a detail object to be displayed as a branch of the current node level

To create an ADF databound tree:

1. Drag the master data collection from the Data Control Palette, and drop it on the page as an ADF Tree. This should be the master collection that represents the root level of the tree.

   Note: The root node must be a collection represented by a method return or accessor return. You cannot use a single object accessor return as the root node of a tree.

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

   JDeveloper displays the Tree Binding Editor, as shown in Figure 8-4.

   Figure 8-4 Tree Binding Editor, Edit Rule Tab

3. In the Edit Rule page of the Tree Binding Editor, define a rule for each node level you want to appear in the tree. To define a rule you must select the following items:

   - Data Collection Definition: Select the data collection that will populate the node level you are defining. The first rule defines the root node level. So, for the first rule, select the same data collection that you dragged from the Data Control Palette (the master collection) to create the tree. To create a branch node, select the appropriate detail collection. For example, to create a root node of users, you would select the `User` collection for the first (root node) rule; to create a branch that displays services requests, you would select the `ServiceRequest` collection in the branch rule.

   - Display Attribute: Select one or more attributes to display at each node level. For example, for a node of users, you might select both the FirstName`` and LastName`` attributes.

   - Branch Rule Accessor: Select the accessor method that returns the detail collection that you want to appear as a branch under the node level you are defining. (As previously mentioned, detail collections are always returned by accessor methods.) The list displays only the accessor methods that return the detail collections for the master collection you selected for the rule. If you choose <none>, the node will not expand to display any detail collections, thus ending the branch. For example, if you are defining the `User` node level and you want to add a branch to the service requests for each user, you would select the accessor method that returns the service request collection. Then, you must define a new rule for the `serviceRequest` node level.

   - Polymorphic Restriction: Optionally, you can define a node-populating rule for an attribute whose value you want to make a discriminator. The rule will be polymorphic because you can define as many node-populating rules as desired for the same attribute, as long as each rule specifies a unique discriminator value. The tree will display a separate branch for each polymorphic rule, with the node equal to the discriminator value of the attribute.

     Tip: Be sure to click Add New Rule after you define each rule. If you click OK instead, the last rule you defined will not be saved. When you click Add New Rule, JDeveloper displays the Show Rules tab of the Tree Binding Editor, where you can verify the rules you have created.

4. Use the Show Rules page of the Tree Binding Editor, shown in Figure 8-5, to:

   - Change the order of the rules

     The order of the rules should reflect the hierarchy that you want the tree to display.

   - Identify the icons you want displayed at each node level

     By default, every node level displays a folder icon. You can use different icons for each node level (represented by a rule) and different icons for the different states of the node: open, closed, end of a branch.

   - Delete rules

   The first rule listed in the Show Rules page of the Tree Binding Editor, populates the root node level of the tree. So, be sure that the first rule populates the logical root node for the tree, depending on the structure of your data model.

   For example, in the sample tree previously shown in Figure 8-3, the first rule would be the one that populates the user nodes. The order of the remaining rules should follow the hierarchy of the nodes you want to display in the tree.

Figure 8-5 Tree Binding Editor, Show Rule Tab

## 8.4.2 What Happens When You Create an ADF Faces Databound Tree

When you drag and drop from the Data Control Palette, JDeveloper does many things for you. For a full description of what happens and what is created when you use the Data Control Palette, see Section 5.2.3, "What Happens When You Create a Component From the Data Control Palette".

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

### 8.4.2.1 Code Generated in the JSF Page

Example 8-3 shows the code generated in a JSF page when you use the Data Control Palette to create a tree. This sample tree displays two levels of nodes: users and service requests. The `User` collection is returned by the `findAllStaff` method.

Example 8-3 Code Generated in the JSF Page for a Databound Tree

    <af:tree value="#{bindings.findAllStaff1.treeModel}" var="node">
       <f:facet name="nodeStamp">
          <af:outputText value="#{node}"/>
       </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 `findAllStaff1` tree binding object in the page definition file. 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.

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.

### 8.4.2.2 Binding Objects Added to the Page Definition File

Example 8-4 shows the code generated in the page definition file for the ADF databound tree.

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 (`findAllStaffIter`) is needed. This iterator iterates over the master collection, which populates the root nodes of the tree. The accessor methods you specified in the node rules return the detail data for each branch.

In the example, the iterator happens to be a method iterator because a method return was dragged from the Data Control Palette and dropped on the page as an ADF tree. If an accessor return had been dragged from the Data Control Palette, this would be an accessor iterator instead of a method iterator. Because a method iterator is used in this example, a corresponding `methodAction` is defined in the `bindings` element. The `methodAction` encapsulates the details about how to invoke the method, which returns the data collections.

The `tree` element is the value binding for all the attributes that are returned by the `findAllStaff` method. The `<nodeDefinition>` elements within the tree element define the rules for populating the nodes of the tree. The `nodeDefinition` elements contain the following subelements and attributes:

- `DefName`: Defines the data collection that will be used to populate the node. For example, the `UserNode` node is populated by the `User` data collection.

- `id`: Defines the name of the node. For example, `UserNode`.

- `AttrNames`: Defines the attributes that will be displayed in the node at runtime. For example, for the `UserNode` node, the tree will display the `firstName` and `lastName` attributes of each user.

- `Accessors`: Defines the accessor method that returns the next branch of the tree. For example, the `UserNode` defines the accessor that returns the `serviceRequestCollectionAssignedTo` accessor method. If the current node is the last node in the tree, this element is not included.

The order of the `nodeDefintion` elements within the page definition file defines the order of the branches in the tree. The first `nodeDefinition` element defines the root node.

For more information about the elements and attributes of the page definition file, see Section A.7, "<pageName>PageDef.xml".

Example 8-4 Binding Objects Added to the Page Definition File for a Databound Tree

    <executables>
        <methodIterator id="findAllStaffIter" Binds="findAllStaff.result"
                        DataControl="SRPublicFacade" RangeSize="10"
                        BeanClass="oracle.srdemo.model.entities.User"/>
    </executables>
    <bindings>
        <methodAction id="findAllStaff" InstanceName="SRPublicFacade.dataProvider"
                      DataControl="SRPublicFacade" MethodName="findAllStaff"
                      RequiresUpdateModel="true" Action="999"
                      ReturnName="SRPublicFacade.methodResults.
                                    SRPublicFacade_dataProvider_findAllStaff_result"/>
        <tree id="findAllStaff1" IterBinding="findAllStaffIter">
          <AttrNames>
            <Item Value="city"/>
            <Item Value="countryId"/>
            <Item Value="email"/>
            <Item Value="firstName"/>
            <Item Value="lastName"/>
            <Item Value="postalCode"/>
            <Item Value="stateProvince"/>
            <Item Value="streetAddress"/>
            <Item Value="userId"/>
            <Item Value="userRole"/>
          </AttrNames>
          <nodeDefinition DefName="oracle.srdemo.model.entities.User" id="UserNode">
            <AttrNames>
              <Item Value="firstName"/>
              <Item Value="lastName"/>
            </AttrNames>
            <Accessors>
              <Item Value="assignedToCollection"/>
            </Accessors>
          </nodeDefinition>
          <nodeDefinition DefName="oracle.srdemo.model.entities.ServiceRequest"
                          id="ServiceRequestNode">
            <AttrNames>
              <Item Value="problemDescription"/>
            </AttrNames>
          </nodeDefinition>
        </tree>
    </bindings>

## 8.4.3 What Happens at Runtime

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 is displayed, the iterator binding on the tree component 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 method specified in the node rule defined in the page definition file. This accessor method is invoked in response to the `DisclosureEvent` event; in other words, whenever a user expands the node the accessor method populates the branch nodes.