Skip Headers
Oracle® Application Development Framework Developer's Guide For Forms/4GL Developers
10g (10.1.3.1.0)

Part Number B25947-01
Go to Documentation Home
Home
Go to Book List
Book List
Go to Table of Contents
Contents
Go to Index
Index
Go to Master Index
Master Index
Go to Feedback page
Contact Us

Go to previous page
Previous
Go to next page
Next
View PDF

15.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, available from the Data Control Palette, 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 15.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 15-4 shows an example of a tree from the SRManage page of the SRDemo application. The tree displays two levels of nodes: staff members and service requests assigned to them. The root nodes display staff members. The branch nodes display open or pending service requests assigned to each staff member.

Figure 15-4 Databound ADF Faces Tree

ADF Tree Component

15.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 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 that node level

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

  • A view link accessor attribute that returns a detail object to be displayed as a branch of the current node level (for information about view link accessors, see Chapter 5, "How to Create Master/Detail Hierarchies Using View Links")

To create the tree on the SRMange page, a view object, StaffWithOpenRequests, was created to return just the users that have open or pending service requests. Another view object, OpenOrPendingServiceRequests, was created to return all the open or pending service requests. A view link was created from the StaffWithOpenRequests view object to the OpenOrPendingServiceRequests view object, thus establishing the master-detail relationship. To add a third-level node, for example, service history, a view link would need to exist from the service request view object to the service history view object. For more information about creating view links, see Section 5.10, "Working with Master/Detail Data".

To display master-detail objects in a tree:

  1. Drag the master object from the Data Control Palette, 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 Tree Binding Editor, as shown in Figure 15-5.

    Figure 15-5 Tree Binding Editor, Edit Rule Tab

    Tree Binding Editor
  3. In the Edit Rule page of the Tree Binding Editor, define a rule for each node level that 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 collection that you dragged from the Data Control Palette to create the tree, which was a master collection.

      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 view link accessor attribute that returns the detail collection that you want to appear as a branch under the node level you are defining. The list displays only the accessor attributes that return the detail collections for the master collection you selected for the rule. If you select <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 attribute that returns the service request collection. Then, you must define a new rule for the ServiceRequest node level.

      View link accessor attributes, which return data collections, are generated when you create a view link. The Branch Rule Accessor field displays all accessor attributes that return detail collections for the master collection selected in the Data Collection Definition field. For more information about view objects, view links, and view link accessors, see Chapter 5, "Querying Data Using View Objects".

    • 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 15-6, 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 15-4, 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 15-6 Tree Binding Editor, Show Rule Tab

Tree Binding Editor, Show Rule Tab

15.4.2 What Happens When You Create ADF Databound Trees

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 12.2.3, "What Happens When You Use 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 tag to the JSF Page. The resulting UI component is fully functional and does not require any further modification.

15.4.2.1 Code Generated in the JSF Page

Example 15-2 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 LoggedInUser collection was used to populate the root node, which displays the users.

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

<h:form>
   <af:tree value="#{bindings.StaffWithOpenRequests.treeModel}" var="node">
     <f:facet name="nodeStamp">
       <af:outputText value="#{node}"/>
     </f:facet>
   </af:tree>
</h:form>

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

15.4.2.2 Binding Objects Defined in the Page Definition File

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

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

<executables>
    <iterator id="StaffWithOpenRequestsIterator" RangeSize="10"
              Binds="StaffWithOpenRequests" DataControl="SRService"/>
</executables>
<bindings>
  <tree id="StaffWithOpenRequests"
        IterBinding="StaffWithOpenRequestsIterator">
    <AttrNames>
      <Item Value="UserId"/>
      <Item Value="FirstName"/>
      <Item Value="LastName"/>
    </AttrNames>
    <nodeDefinition DefName="oracle.srdemo.model.queries.StaffWithOpenRequests"
                    id="StaffWithOpenRequestsNode">
      <AttrNames>
        <Item Value="FirstName"/>
        <Item Value="LastName"/>
      </AttrNames>
      <Accessors>
        <Item Value="OpenOrPendingServiceRequests"/>
      </Accessors>
    </nodeDefinition>
    <nodeDefinition id="OpenOrPendingServiceRequestsNode"
               DefName="oracle.srdemo.model.queries.OpenOrPendingServiceRequests">
      <AttrNames>
        <Item Value="Status"/>
        <Item Value="ProblemDescription"/>
      </AttrNames>
    </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 return 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 Section A.6, "<pageName>PageDef.xml".

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

15.4.4 What You May Need to Know About Adding Command Links to Tree Nodes

The tree component on the SRManage page of the SRDemo application, which displays staff members in the root nodes and service requests in the branch nodes, was created using the default tree component available from the Data Control Palette. However, each node of the tree contains a command link that dynamically displays additional detail data related to that node in a separate UI component. For example, if the user clicks a staff member, the related expertise areas (detail objects) are displayed in a table to the right of the tree, as shown in Figure 15-7.

Figure 15-7 SRManage Page Displaying a Tree and Dynamic Detail Table

SRMange Page

To achieve this functionality, an ADF Faces switcher component was manually added to the tree tag's nodestamp facet to dynamically display the data from detail objects when the user clicks a command link.

In the switcher component, which is shown in Example 15-4, the facetName attribute contains a JSF binding on the SRManage backing bean, which is configured as a managed bean in the faces-config.xml file. The backing bean has a treeLevel property of type Map that is declaratively defined as a managed property in the faces-config.xml file.

Example 15-4 ADF Faces switcher Component

<af:switcher facetName="#{backingSRManage.treeLevel[node.hierType.viewDefName]}">
  <f:facet name="StaffNode">
    <af:commandLink text="#{node}"
                  action="#{backing_SRManage.staffLinkDrilldown}"
                  actionListener="#{bindings.setCurrentStaffRowWithKey.execute}"/>
  </f:facet>
  <f:facet name="ServiceRequestsNode">
    <af:panelGroup>
      <af:outputText  value="[#{node.Status}] "/>
        <af:commandLink text="#{node.ProblemDescription}"
           action="#{backing_SRManage.problemLinkDrilldown}"
           actionListener="#{bindings.setCurrentProblemAndAssigneeRows.execute}"/>
    </af:panelGroup>
  </f:facet>
</af:switcher>

The managed property definition in the faces-config.xml contains information that injects the key-value pairs (viewdefinitionname, facetname) into the treeLevel Map, as shown in Example 15-5. The Map is used to display a different presentation in the tree for each different view object type.

Example 15-5 The treeLevel Managed Property Definition in the faces-config.xml File

<managed-bean>
    <managed-bean-name>backing_SRManage</managed-bean-name>
    ...
    <managed-property>
      <property-name>treeLevel</property-name>
      <map-entries>
        <key-class>java.lang.String</key-class>
        <value-class>java.lang.String</value-class>
        <map-entry>
          <key>oracle.srdemo.model.queries.StaffWithOpenRequests</key>
          <value>StaffNode</value>
        </map-entry>
        <map-entry>
          <key>oracle.srdemo.model.queries.OpenOrPendingServiceRequests</key>
          <value>ServiceRequestsNode</value>
        </map-entry>
      </map-entries>
    </managed-property>
  </managed-bean>

When you add command links to nodes in a tree, at runtime a user could click a link that is not the current object in the iterator that is populating the tree. (The current object in the iterator is the one displayed the last time the user opened a tree node.) Therefore, to display the correct detail object, the command links must be bound to operations or methods that programmatically set the current object in the iterator. For example, in the SRManage page, the command link on the service request node is bound to the setCurrentProblemAndAssigneeRows method, which programmatically sets the current object. For more information about manually setting the current object in a command component, see Section 14.7, "Setting the Current Object Using a Command Component". For more information about the ADF Faces switcher component, refer to the ADF Faces Javadoc.