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

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

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

15 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 Section 19.7, "Creating Selection Lists".

15.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 you may recall from Chapter 5, "Querying Data Using 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. ADF uses the view link to associate a row of one view object instance (the master object) with one or more rows of another view object instance (the detail object).

View links support two different types of master-detail coordination: view link accessor attributes and data model view link instances (for more information, see Section 27.1.3, "Understanding View Link Accessors Versus Data Model View Link Instances"). However, when displaying master-detail data on a page using ADF data binding, you exclusively use data model view link instances, which support active data model master-detail coordination. To enable active data model master-detail coordination, you must add both the master view object and the detail view object instances to the application module data model (for more information, see Section 5.10.4.3, "How to Enable Active Master/Detail Coordination in the Data Model".) For example, in the SRDemo application, there is a view link from the ServiceRequests view object to the ServiceHistories view object based on the Svr_Id attribute (service request ID). Both the master and detail view objects have been added to the application module data model. So, a change in the current row of the master view object instance causes the rowset of the detail view object instance to refresh to include the details for the current master.

When objects have a master-detail relationship, you can declaratively create pages that display the data from both objects simultaneously. For example, the SRDemo application has a page that displays a service request in a form at the top of the page and its related service history in a table at the bottom of the page. This is possible because the service request and service history objects have a master-detail relationship. In this example, the service request is the master object and the service history is the detail object. The ADF iterators automatically manage the synchronization of the detail data objects displayed for a selected master data object.

Read this chapter to understand:

15.2 Identifying Master-Detail Objects on the Data Control Palette

JDeveloper enables you to declaratively create pages that display master-detail data using the Data Control Palette. The Data Control Palette 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.10.4.3, "How to Enable Active Master/Detail Coordination in the Data Model".

Figure 15-1 shows two master-detail related collections in the Data Control Palette of the SRDemo application. The ServiceRequests collection is an instance of the ServiceRequests view object, and the ServiceHistories collection, which appears as a child of the ServiceRequests collection, is an instance of the ServiceHistories view object. The master-detail hierarchy on the Data Control Palette reflects the hierarchy defined in the SRService application module data model, as shown in Figure 15-2. The hierarchy was established by creating a view link from the ServiceRequests view object to the ServiceHistories view object. Next, an instance of the resulting detail view object, ServiceHistories via ServicesHistoriesForServiceRequest1, has been added to the application module data model, and named ServiceHistories, as shown in Figure 15-2.

Tip:

The master-detail hierarchy displayed in the Data Control Palette does not reflect the cardinality of the relationship (for example, 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 15-1 Master-Detail Objects on the Data Control Palette

Master-detail objects on the Data Control Palette

Figure 15-2 Master-Detail Hierarchy Defined in the Application Module Data Model

Master-Detail Hierarchy in the Application Module Data Model

In the SRDemo application, the view link between the ServiceRequests view object and ServiceHistories view object is a one-way relationship. If the view link was bi-directional and both sets of master and detail view objects were added to the application module data model, then the Data Control Palette would also display the ServiceHistories collection at the same node level as the ServiceRequests collection, and the detail instance of the ServiceRequests collection as child of the ServiceHistories collection.

When creating a page that displays master-detail objects, be sure to correctly identify which object is the master and which is the detail for your particular purposes. Otherwise, you may not display the desired data on the page.

For example, if you want to display a user and all the related expertise areas to which the user is assigned, then User would be the master object. However, if you wanted to display an expertise area and all the users is assigned to it, then expertiseArea would be the master object. The detail objects displayed on a page depend on which object is the master.

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 bi-directional. If both sets of master-detail view objects resulting from a bi-directional view link are added to the application module data model, then instances of both sets of view objects will appear independently on the Data Control Palette.

For more information about the icons displayed on the Data Control Palette, see Section 12.2.1, "How to Understand the Items on the Data Control Palette".

15.3 Using Tables and Forms to Display Master-Detail Objects

JDeveloper enables you to create a master-detail browse page in a single declarative action using the Data Control Palette—you do not need to write any extra code, even the navigation is included. The Data Control Palette provides pre-built master-detail widgets that display both the master and detail objects on the same page as any combination of read-only tables and forms. All you have to do is drop the detail collection on the page and choose the type of widget you want to use.

The pre-built master-detail widgets available from the Data Control Palette include range navigation that enables the user to scroll through the data objects in collections. The the table provided by the pre-built master-detail widgets includes a selection facet and Submit command button. By default, all attributes of the master and detail objects are included in the master-detail widgets as text fields (in forms) or columns (in tables). You can delete unwanted attributes by removing the text field or column from the page.

Tip:

If you do not want to use the pre-built master-detail widgets, you can drag and drop the master and detail objects individually as tables and forms on a single page or on separate pages. For more information about creating individual forms and tables, see Chapter 13, "Creating a Basic Page" or Chapter 14, "Adding Tables".

When you add master-detail components to a page, the iterator bindings are responsible for exposing data to the components on the page. The iterator bindings bind to the underlying rowset iterators. At runtime, the active data model and the rowset iterator for the detail view object instance keep the rowset of the detail view object refreshed to the correct set of rows for the current master row as that current row changes.

Figure 15-3 shows an example of a pre-built master-detail widget, which display a service request in a form at the top of the page and all the related service history in a table at the bottom of the page. When the user scrolls through the master data, the page automatically displays the related detail data.

Figure 15-3 Pre-Built Data Control Palette Master-Detail Widget

Default master-detail widget

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

The Data Control Palette enables you to create both the master and detail widgets on one page with a single declarative action using pre-built master-detail forms and tables. For information about displaying master and detail data on separate pages, see Section 15.3.4, "What You May Need to Know About Master-Detail on Separate Pages".

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

  1. From the Data Control Palette, locate the detail object, as was previously described in Section 15.2, "Identifying Master-Detail Objects on the Data Control Palette".

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

  3. In the context menu, choose one of the following Master-Details widgets:

    • 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 objects.

    • 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 are displayed in the table below it.

    If you want to modify the default forms or tables, see Chapter 13, "Creating a Basic Page" or Chapter 14, "Adding Tables".

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

When you drag and drop from the Data Control Palette, JDeveloper does many things for you, including adding code to the JSF page and corresponding entries in the page definition file. 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".

15.3.2.1 Code Generated in the JSF Page

The JSF code generated for a pre-built master-detail widget is basically the same as the JSF code generated when you use the Data Control Palette to create a basic read-only table or form. For more information, see Chapter 13, "Creating a Basic Page" and Chapter 14, "Adding Tables". If you are building your own master-detail widgets, you might want to consider including similar components that are automatically included in the pre-built master-detail tables and forms.

The tables and forms in the pre-built 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 pre-built 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 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 would automatically omit the range navigation components.) For more information about range navigation, see Section 13.4, "Incorporating Range Navigation into Forms".

By default, tables in a pre-built master-detail widget include a tableSelectOne selection facet and a Submit button that enables the user to select a specific object in the collection. The default button is not automatically bound to a method or operation. So to get the selection facet to work, you would need to add an action binding to the button. For example, you could bind the button to a method that enables the user to edit the selected data object, as was done in the SRMain page of the SRDemo application. For more information about selection facets, see Section 17.3, "Creating Command Components to Execute Methods".

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, panelForm 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 re-rendered 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 re-rendered when the user simply makes a selection in the facet: only the detail component needs to be re-rendered to display the new data. For more information about partial rendering, see Section 19.4, "Enabling Partial Page Rendering".

15.3.2.2 Binding Objects Defined in the Page Definition File

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

The executables element defines two iterators: one for the service requests (which is the master object) and one for the service history (which is 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 active data model and the rowset iterator for the detail view object instance keep the rowset 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 15.3.3, "What Happens at Runtime").

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.6, "<pageName>PageDef.xml".

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

<executables>
    <iterator id="ServiceRequestsIterator" RangeSize="10"
              Binds="ServiceRequests" DataControl="SRService"/>
    <iterator id="ServiceHistoriesIterator" RangeSize="10"
              Binds="ServiceHistories" DataControl="SRService"/>
  </executables>
  <bindings>
    <attributeValues id="SvrId" IterBinding="ServiceRequestsIterator">
      <AttrNames>
        <Item Value="SvrId"/>
      </AttrNames>
    </attributeValues>
    <attributeValues id="Status" IterBinding="ServiceRequestsIterator">
      <AttrNames>
        <Item Value="Status"/>
      </AttrNames>
    </attributeValues>
    <attributeValues id="RequestDate" IterBinding="ServiceRequestsIterator">
      <AttrNames>
        <Item Value="RequestDate"/>
      </AttrNames>
    </attributeValues>
    ...
    <action id="First" RequiresUpdateModel="true" Action="12"
            IterBinding="ServiceRequestsIterator"/>
    <action id="Previous" RequiresUpdateModel="true" Action="11"
            IterBinding="ServiceRequestsIterator"/>
    <action id="Next" RequiresUpdateModel="true" Action="10"
            IterBinding="ServiceRequestsIterator"/>
    <action id="Last" RequiresUpdateModel="true" Action="13"
            IterBinding="ServiceRequestsIterator"/>
    <table id="ServiceRequestsServiceHistories"
           IterBinding="ServiceHistoriesIterator">
      <AttrNames>
        <Item Value="SvrId"/>
        <Item Value="LineNo"/>
        ...
      </AttrNames>
    </table>
  </bindings>

15.3.3 What Happens at Runtime

As was previously mentioned in Section 12.5.2.2, "Binding Objects Defined in the executables Element", ADF iterators are associated with underlying RowSetIterator objects, which manage which data objects, or rows, are currently displayed on a page. At runtime, the rowset iterators manage the data displayed in the master and detail components.

Both the master and detail rowset iterators listen to rowset navigation events, such as the user selecting a specific row or clicking the range navigation buttons, and display the appropriate rows in the UI. In the case of the default master-detail components, the rowset navigation events are the command buttons on a form (First, Previous, Next, Last) or the selection facet and Submit button on a table.

The rowset 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 rowset iterator listens for row navigation events in both the master and detail collections. If a rowset navigation event occurs in the master collection, the detail rowset iterator automatically executes and returns the detail rows related to the current master row.

15.3.4 What You May Need to Know About Master-Detail 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 Control Palette, 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 SRDemo application the service requests and service history are displayed on the SRMain page. However, the page could display the service request only, and instead of showing the service history, it could provide a button called Details. If the user clicks the Details button, the application would navigate to a new page that displays all the related service history in a table. A button on the service history 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 Control Palette. (For information about using the forms or tables, see Chapter 13, "Creating a Basic Page" or Chapter 14, "Adding Tables".) Remember that the detail object iterator manages the synchronization of the master and detail data. So, be sure to drag the appropriate detail object from the Data Control Palette when you create the page to display the detail data (see Section 15.2, "Identifying Master-Detail Objects on the Data Control Palette").

To handle the page navigation, 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 Control Palette. Each button must specify a navigation rule outcome value in the action attribute. In the faces-config.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 Chapter 16, "Adding Page Navigation".

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.

    • Delete rules

    Note:

    You cannot change the icon displayed in an ADF Faces or JSF tree component.

    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.

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

Figure 15-8 shows an example of a tree table that displays three levels of nodes: users, service requests, and service history. Each root node represents an individual user. The branches off the root nodes display the service requests associated with that user. Each service request node branches to display the service history for each service request.

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 the tree table shown in Figure 15-8, it was necessary to create view links from the user view object to the service request view object, and another view link from the service requests view object to the service history view object. For more information about creating view links, see Section 5.10, "Working with Master/Detail Data".

Figure 15-8 Databound ADF Faces Tree Table

ADF Faces Tree Table

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.

The ADF Faces treeTable component includes the following built-in functionality:

15.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. For more information, see Section 15.4.1, "How to Display Master-Detail Objects in Trees".

15.5.2 What Happens When You Create a Databound Tree Table

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 table using the Data Control Palette, 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.

15.5.2.1 Code Generated in the JSF Page

Example 15-6 shows the code generated in a JSF page when you use the Data Control Palette to create a tree table. This sample tree table displays three levels of nodes: users, service requests, and service history.

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, which in the example is the LoggedInUser tree binding object. 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 15-6 Code Generated in the JSF Page for a Databound ADF Faces Tree Table

<h:form>
  <af:treeTable value="#{bindings.LoggedInUser.treeModel}" var="node">
    <f:facet name="nodeStamp">
      <af:column>
        <af:outputText value="#{node}"/>
      </af:column>
    </f:facet>
    <f:facet name="pathStamp">
      <af:outputText value="#{node}"/>
    </f:facet>
  </af:treeTable>
</h: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.

15.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. For more information about tree binding objects, see Section 15.4.2.2, "Binding Objects Defined in the Page Definition File".

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

15.6 Using an Inline Table to Display Detail Data in a Master Table

As you may recall from Section 14.5, "Adding Hidden Capabilities to a Table", you can use the detailStamp facet in a table to hide or show additional information about a specific data object displayed in the table. When you add a component to this facet, the table displays an additional column labeled Details, which displays the additional information. It includes a toggle mechanism that enables the user to hide or show the information displayed in the Details column in a manner similar to the mechanism in an ADF Faces tree or treeTable component. In the case described in Section 14.5, "Adding Hidden Capabilities to a Table", the additional information was a single attribute from the same data collection that populates the table.

Using master-detail collections on the Data Control Palette, you can declaratively add an inline table to the detailStamp facet that displays additional information from a detail collection. A master collection is used to populate the main table and a detail collection is used to populate the inline table.

Figure 15-9 shows how an inline table of service requests can be embedded in a table of service request staff. If the user clicks the Show link in the Details column, which is built into the table facet, an inline table of service requests is displayed under the selected row of the table. The main table is populated by a master collection of users and displays the user's first and last name. The inline table is populated by a detail collection of service requests and displays the service request problem description and status.

Figure 15-9 Inline Table Displaying Information from a Detail Collection

Master Table, Inline Detail Table

15.6.1 How to Display Detail Data Using an Inline Table

Using the Data Control Palette, you can create both the main table and the inline table in a single declarative action. Since an inline table is similar to a tree table, you use the Tree Binding Editor to define the rules that populate the main table and the inline detail table. There must be one rule for the main table and one rule for the inline detail table. Each rule defines the following properties:

  • The data collection that populates the table

  • The attributes from the data collection that are displayed in the table

The rule for the main table must also specify a view link accessor attribute that returns the detail collection that will populate the inline table. For information about view links accessors, see Section 5.10.2, "How to Create Master/Detail Hierarchies Using View Links".

To create a master table with an inline detail table:

  1. Drag a master data object from the Data Control Palette, and drop it on the page. This should be the master object that you want to populate the main table.

  2. In the context menu, choose Tables > ADF Master Table, Inline Detail Table.

    JDeveloper displays the Tree Binding Editor (previously shown in Figure 15-5).

  3. In the Edit Rule page of the Tree Binding Editor, define a rule for populating the main table and another rule for populating the inline table. To define a rule you must select the following items:

    • Data Collection Definition: Select the data collection that will populate the table you are defining. The first rule defines the main table. So, for the first rule, select the same data collection that you dragged from the Data Control Palette (the master collection). When defining the rule for the inline table, select the appropriate detail collection. For example, to create a main table of users, you would select the User collection for the first rule; to create an inline table that displays service requests related to a user, you would select the ServiceRequest collection in the branch rule.

    • Display Attribute: Select one or more attributes to display in the table you are defining. Each attribute is a column in the table. For example, if the main table is displaying users, you might select both the firstName and lastName attributes.

    • Branch Rule Accessor: If you are defining the rule for the main table, select the accessor attribute that returns the detail collection that you want to appear in the inline detail table. The list displays only the accessor attributes that return the detail collections for the master collection you selected for the rule. If you are defining the rule for the inline table, select <none>, because you cannot embed a table inside the inline table.

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

      Tip:

      Be sure to click the Add New Rule button after you define each rule. If you click the OK button 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 rule that populates the main table must be first in the list

    • Identify the icons you want displayed for the expand and collapse mechanism

      Only the main table uses the icons, so if you want to use an icon other than the default, specify it in the rule for the main table.

      The default open icon is a solid down arrow with a minus sign, while the default closed icon is a solid right arrow with a plus sign

    • Delete rules

15.6.2 What Happens When You Create an Inline Detail Table

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

15.6.2.1 Code Generated in the JSF Page

When you create a master table and an inline detail table using the Data Control Palette, JDeveloper adds binding objects to the page definition file, and it also adds the table and facet to the JSF page. The resulting UI components are fully functional and do not require any further modification.

Example 15-7 shows the code generated in the JSF page. This sample displays users in the main table and service requests in the inline detail table. The main table is defined the same as any other ADF databound table. It is bound to the LoggedInUser binding object in the page definition file, which is a tree binding object. The columns in the main table display the user's first name and last name. The table includes a detailStamp facet in which the detail table is defined. The detail table is also bound to the LoggedInUser tree binding object, and the columns are set up to display the data from the service request collection. As with tree components, the page definition file defines the accessor attribute that returns the detail collection.

Example 15-7 JSF Code Created for the Master Table with an Inline Detail Table

<af:table rows="#{bindings.LoggedInUser.rangeSize}"
          emptyText="#{bindings.LoggedInUser.viewable ? \'No rows yet.\' :
                       \'Access Denied.\'}"
          var="row" value="#{bindings.LoggedInUser.treeModel}">
  <af:column headerText="#{bindings.LoggedInUser.labels.FirstName}"
             sortable="false" sortProperty="FirstName">
    <af:outputText value="#{row.FirstName}"/>
  </af:column>
  <af:column headerText="#{bindings.LoggedInUser.labels.LastName}"
             sortable="false" sortProperty="LastName">
    <af:outputText value="#{row.LastName}"/>
  </af:column>
  <f:facet name="detailStamp">
    <af:table rows="#{bindings.LoggedInUser.rangeSize}"
              emptyText="No rows yet." var="detailRow"
              value="#{row.children}">
      <af:column headerText="#{row.children[0].labels.Status}"
                 sortable="false" sortProperty="Status">
        <af:outputText value="#{detailRow.Status}"/>
      </af:column>
      <af:column headerText="#{row.children[0].labels.ProblemDescription}"
                 sortable="false" sortProperty="ProblemDescription">
        <af:outputText value="#{detailRow.ProblemDescription}"/>
      </af:column>
    </af:table>
  </f:facet>
</af:table>

15.6.2.2 Binding Objects Defined in the Page Definition File

Example 15-8 shows the binding objects added to the page definition file for a master table with an inline detail table. The executables element defines an iterator binding named LoggedInUserIterator, which displays data from the LoggedInUser collection in the main table. No iterator binding is needed for the detail collection, because the accessor attribute referenced in the tree binding object returns the detail data that is related to the currently selected master data.

In the bindings element, the tree binding object populates the data in the master and detail tables. The nodeDefintion elements define the attributes that are displayed in the columns of the master and detail tables. The first nodeDefinition element defines the data in the master table, and the second one defines the data in the inline detail table. For more information about tree binding objects, see Section 15.4.2, "What Happens When You Create ADF Databound Trees".

Example 15-8 Binding Objects Added to the Page Definition File for a Master Table with an Inline Detail Table

<executables>
  <iterator id="LoggedInUserIterator" RangeSize="10" Binds="LoggedInUser"
            DataControl="SRService"/> 
</executables>
<bindings>
  <tree id="LoggedInUser" IterBinding="LoggedInUserIterator">
    <AttrNames>
      <Item Value="UserId"/>
      <Item Value="Email"/>
      <Item Value="FirstName"/>
      <Item Value="LastName"/>
    </AttrNames>
    <nodeDefinition DefName="oracle.srdemo.model.queries.LoggedInUser"
                    id="LoggedInUserNode">
      <AttrNames>
        <Item Value="FirstName"/>
        <Item Value="LastName"/>
      </AttrNames>
      <Accessors>
        <Item Value="ServiceRequestsByStatus"/>
      </Accessors>
    </nodeDefinition>
    <nodeDefinition DefName="oracle.srdemo.model.queries.ServiceRequestsByStatus"
                    id="ServiceRequestsByStatusNode">
      <AttrNames>
        <Item Value="Status"/>
        <Item Value="ProblemDescription"/>
      </AttrNames>
    </nodeDefinition>
  </tree>
</bindings>

15.6.3 What Happens at Runtime

When the user hides or shows the details of a row (by clicking the Hide or Show links), the table generates a DisclosureEvent event, which expands or collapses the inline detail table. The isExpanded method on this event determines whether the user is showing or hiding the detail table.

The DisclosureEvent event has an associated listener. The DisclosureListener attribute on the table is implicitly 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 DisclosureEvent event. For example, if the user clicks on the Show link, the accessor attribute is invoked to populate the data in the inline table.