Oracle® Application Development Framework Developer's Guide 10g Release 3 (10.1.3.0) Part Number B28967-02 |
|
|
View PDF |
This chapter describes how to create various types of pages that display master-detail related data.
This chapter includes the following sections:
Section 8.1, "Introduction to Displaying Master-Detail Data"
Section 8.2, "Identifying Master-Detail Objects on the Data Control Palette"
Section 8.3, "Using Tables and Forms to Display Master-Detail Objects"
Section 8.5, "Using Tree Tables to Display Master-Detail Objects"
Section 8.6, "Using an Inline Table to Display Detail Data in a Master Table"
For information about using a selection list to populate a collection with a key value from a related master or detail collection, see Section 11.7, "Creating Databound Dropdown Lists".
In ADF, a master-detail relationship refers to two data objects in the data control hierarchy that are logically related in such a way that an instance of one object automatically contains a related instance of the other object. For example, in the SRDemo application, when a data control method returns a collection of service requests, each service-request object contains a list of related service-history objects. The service-history objects are returned by an accessor that is a child of the parent method in the data control hierarchy. Usually, a master-detail relationship in the data control is established by one or more unique attributes that both objects share or by an object hierarchy. For example, in the SRDemo application the serviceRequest
collection and the serviceHistoryCollection
have a master-detail relationship, because both collections contain the svrId
attribute (the service request number). You can also have master-detail relationships between collections and single objects. For example, each object in a collection of service requests could contain a single user object to which that service request is assigned.
Tip:
In TopLink and traditional relational databases master-detail relationships are called foreign-key relationships.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:
Master-detail relationships in ADF
How to identify master-detail objects on the Data Control Palette
How to display master-detail objects in tables, forms, trees, tree tables, and inline tables
How to display master-detail objects on different pages that are connected by a navigation component
How ADF iterators manage the concurrency of master and detail objects
The binding objects created when you use the Data Control Palette to create a master-detail UI component
JDeveloper enables you to declaratively create master-detail pages using the Data Control Palette. The Data Control Palette displays master-detail related objects in a hierarchy, where the detail object is displayed as an accessor return under the master object. In the data control, accessor returns are always detail objects in a master-detail relationship.
Figure 8-1 shows the Data Control Palette for the SRDemo application. Because the serviceHistory
and ServiceRequest
objects have a master-detail relationship, the accessor return serviceHistoryCollection
appears under the ServiceRequest
method return. In this case, the accessor return is a collection of service history objects related to a service request object. Method returns are always collections, but accessor returns can be either collections or single objects.
Tip:
By default, when data controls are created from TopLink POJOs (or session beans over POJOs), the names of accessor returns that are collections end inCollection
. For example, serviceHistoryCollection
.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).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:
In the Data Control Palette, the attributes shared by both the master and detail objects appear under only one of the objects, not both. For example, in the SRDemo application Data Control Palette, thesrvId
attribute appears under the ServiceRequest
master node, but not the serviceHistoryCollection
detail node.
Also, in some cases, the master collection appears as an accessor return under a detail collection. For example, in Figure 8-1, ServiceRequest
, which is a master collection, appears as an accessor return under the serviceHistoryCollection
node, which is a detail collection. In this case, the common attribute shared by these collections creates a recursive relationship in the data control. In most cases, you would never use the accessor return that appears as a result of such a recursion to create a UI component.
For more information about the icons displayed on the Data Control Palette, see Section 5.2.1, "How to Understand the Items on the Data Control Palette".
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 6, "Creating a Basic Page" or Chapter 7, "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. The rowset iterator for the detail object is responsible for exposing the correct detail data when a specific master object is displayed or selected on the page.
Figure 8-2 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.
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 8.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:
From the Data Control Palette, locate the detail object, as was previously described in Section 8.2, "Identifying Master-Detail Objects on the Data Control Palette".
Drag and drop the detail object onto the JSF page.
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.
This widget is available only when both the master and detail objects are collections.
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.
This widget is available only when both the master and detail objects are collections.
Note:
If an object is not a collection, but rather just a single data item, JDeveloper automatically excludes the range navigation from the default widget.Also, accessor returns can be collections or single objects. Single objects can be displayed only in forms. Consequently, the master-detail widgets available from the Data Control Palette context menu differ depending on whether the accessor return is a collection or a single object.
If you want to modify the default forms or tables, see Chapter 6, "Creating a Basic Page" or Chapter 7, "Adding Tables".
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 5.2.3, "What Happens When You Use the Data Control Palette".
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 6, "Creating a Basic Page" and Chapter 7, "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 6.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 10.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 11.4, "Enabling Partial Page Rendering".Example 8-1 shows the page definition file created for a master-detail page that was created by dropping the serviceHistoryCollection
accessor return, which is a detail collection under the ServiceRequest
method return, on the page as an ADF Master Form, Detail Table.
The executables
element defines a method iterator for the service requests (which is the master object) and an accessor iterator for the service history (which is the detail object). The accessor iterator contains a MasterBinding
attribute, which references the method iterator for the master object. This reference to the master iterator enables the detail iterator to expose the correct detail data for the current master object (for more information, see Section 8.3.3, "What Happens at Runtime").
The bindings
element defines a methodAction
object, which invokes the method iterator for the master collection, and 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.7, "<pageName>PageDef.xml".
Example 8-1 Binding Objects Defined in the Page Definition for a Master-Detail Page
<executables> <methodIterator id="findAllServiceRequestIter" Binds="findAllServiceRequest.result" DataControl="SRPublicFacade" RangeSize="10" BeanClass="oracle.srdemo.model.ServiceRequest"/> <accessorIterator id="serviceHistoryCollectionIterator" RangeSize="10" Binds="serviceHistoryCollection" DataControl="SRPublicFacade" BeanClass="oracle.srdemo.model.ServiceHistory" MasterBinding="findAllServiceRequestIter"/> </executables> <bindings> <methodAction id="findAllServiceRequest" InstanceName="SRPublicFacade.dataProvider" DataControl="SRPublicFacade" MethodName="findAllServiceRequest" RequiresUpdateModel="true" Action="999" ReturnName="SRPublicFacade.methodResults.SRPublicFacade_ dataProvider_findAllServiceRequest_result"/> ... <attributeValues id="assignedDate" IterBinding="findAllServiceRequestIter"> <AttrNames> <Item Value="assignedDate"/> </AttrNames> </attributeValues> <attributeValues id="problemDescription" IterBinding="findAllServiceRequestIter"> <AttrNames> <Item Value="problemDescription"/> </AttrNames> </attributeValues> <action id="First" RequiresUpdateModel="true" Action="12" IterBinding="findAllServiceRequestIter"/> <action id="Previous" RequiresUpdateModel="true" Action="11" IterBinding="findAllServiceRequestIter"/> <action id="Next" RequiresUpdateModel="true" Action="10" IterBinding="findAllServiceRequestIter"/> <action id="Last" RequiresUpdateModel="true" Action="13" IterBinding="findAllServiceRequestIter"/> <table id="ServiceRequestserviceHistoryCollection" IterBinding="serviceHistoryCollectionIterator"> <AttrNames> <Item Value="lineNo"/> <Item Value="nextLineItem"/> ... </AttrNames> </table> </bindings>
As was previously mentioned in Section 5.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. It listens to the row navigation events in both the master and detail collections. The MasterBinding
attribute on the detail iterator definition in the page definition file tells the detail rowset iterator which master iterator to listen to. 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.
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 6, "Creating a Basic Page" or Chapter 7, "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 8.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 9, "Adding Page Navigation".
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 8.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 8-3 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.
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
An accessor method that returns a detail object to be displayed as a branch of the current node level
To display master-detail objects in a tree:
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.
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.In the context menu, choose Trees > ADF Tree.
JDeveloper displays the Tree Binding Editor, as shown in Figure 8-4.
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 accessor method 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 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.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.
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 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.
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 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.
Example 8-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 User
collection is the root node and is returned by the findAllStaff
method.
Example 8-2 Code Generated in the JSF Page for a Databound Tree
<h:form> <af:tree value="#{bindings.findAllStaff1.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 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.
Example 8-3 shows the binding objects defined in the page definition file for the ADF databound tree.
Example 8-3 Binding Objects Defined 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>
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.
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 collection.
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 method 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.7, "<pageName>PageDef.xml".
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 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.
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 8-6 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.
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:
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 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.
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 8.4.1, "How to Display Master-Detail Objects in 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 5.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.
Example 8-4 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 findAllStaff1
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 8-4 Code Generated in the JSF Page for a Databound ADF Faces Tree Table
<h:form> <af:treeTable value="#{bindings.findAllStaff1.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.
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 8.4.2.2, "Binding Objects Defined in the Page Definition File".
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 method specified in the node rule defined in the page definition file. This accessor method 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.
As you may recall from Section 7.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 7.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 8-7 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.
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 an accessor method that returns the detail collection that will populate the inline table.
To create a master table with an inline detail table:
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.
Note:
You cannot use a single-object accessor return to create a table.In the context menu, choose Tables > ADF Master Table, Inline Detail Table.
JDeveloper displays the Tree Binding Editor (previously shown in Figure 8-4).
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 method that returns the detail collection that you want to appear in the inline detail table. The list displays only the accessor methods 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.
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.Use the Show Rules page of the Tree Binding Editor, shown in Figure 8-5, 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
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 Use the Data Control Palette".
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 8-5 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 User
collection is returned by the findAllStaff
method. The main table is defined the same as any other ADF databound table. It is bound to the findAllStaff1
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 findAllStaff1
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 method that returns the detail collection.
Example 8-5 JSF Code Created for the Master Table with an Inline Detail Table
<af:table rows="#{bindings.findAllStaff1.rangeSize}" emptyText="#{bindings.findAllStaff1.viewable ? \'No rows yet.\' : \'Access Denied.\'}" var="row" value="#{bindings.findAllStaff1.treeModel}"> <af:column headerText="#{bindings.findAllStaff1.labels.firstName}" sortable="false" sortProperty="firstName"> <af:outputText value="#{row.firstName}"/> </af:column> <af:column headerText="#{bindings.findAllStaff1.labels.lastName}" sortable="false" sortProperty="lastName"> <af:outputText value="#{row.lastName}"/> </af:column> <f:facet name="detailStamp"> <af:table rows="#{bindings.findAllStaff1.rangeSize}" emptyText="No rows yet." var="detailRow" value="#{row.children}"> <af:column headerText="#{row.children[0].labels.problemDescription}" sortable="false" sortProperty="problemDescription"> <af:outputText value="#{detailRow.problemDescription}"/> </af:column> <af:column headerText="#{row.children[0].labels.status}" sortable="false" sortProperty="status"> <af:outputText value="#{detailRow.status}"/> </af:column> </af:table> </f:facet> </af:table>
Example 8-6 shows the binding objects added to the page definition file for a master table with an inline detail table. The executables
element defines the findAllStaffIter
iterator binding object, which iterates over the User
collection that populates the main table. No iterator is needed for the detail collection, because the accessor method referenced in the tree binding object returns the detail data that is related to the currently selected master data.
In the bindings
element, the methodAction
binding object invokes the method that returns the User
collection. 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 8.4.2, "What Happens When You Create ADF Databound Trees".
Example 8-6 Binding Objects Added to the Page Definition File for a Master Table with an Inline Detail Table
<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"/> <Item Value="status"/> </AttrNames> </nodeDefinition> </tree> </bindings>
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 method specified in the node rule defined in the page definition file. This accessor method is invoked in response to a DisclosureEvent
event. For example, if the user clicks on the Show link, the accessor method is invoked to populate the data in the inline table.