This chapter describes how to create various types of pages that display master-detail related data.
This chapter includes the following sections:
Section 24.1, "Introduction to Displaying Master-Detail Data"
Section 24.2, "Identifying Master-Detail Objects on the Data Controls Panel"
Section 24.3, "Using Tables and Forms to Display Master-Detail Objects"
Section 24.4, "Using Trees to Display Master-Detail Objects"
Section 24.5, "Using Tree Tables to Display Master-Detail Objects"
Section 24.6, "Using Selection Events with Trees and Tables"
For information about using a selection list to populate a collection with a key value from a related master or detail collection, see Chapter 25, "Creating Databound Selection Lists and Shuttles".
In ADF Business Components, a master-detail relationship refers to two view object instances that are related by a view link. As described in Section 5.1, "Introduction to View Objects", a view link represents the relationship between two view objects, which is usually, but not necessarily, based on a foreign-key relationship between the underlying data tables. The view link associates a row of one view object instance (the master object) with one or more rows of another view object instance (the detail object).
To display master-detail data on a page using ADF data binding, you exclusively use data model view link instances, which support master-detail coordination. When using ADF Business Components in combination with the ADF Model layer and ADF Faces UI components, the data model automatically updates to reflect any changes to the row sets of these business objects.
To enable master-detail coordination, you must add both the master view object and the detail view object instances to the application module data model. For example, in the Fusion Order Demo application, there is a view link from the ProductsVO
view object to the WarehouseStockLevelsVO
view object based on the ProductId
attribute, both contained in the application module data model, as shown in Figure 24-1. A change in the current row of the master view object instance causes the row set of the detail view object instance to refresh to include the details for the current master.
When objects have a master-detail relationship, you can declaratively create pages that display the data from both objects simultaneously. For example, the page shown in Figure 24-2 displays a country code in a form at the top of the page and its related states and provinces in a table at the bottom of the page. This is possible because the objects have a master-detail relationship. In this example, the Country Code
is the master object and States
is the detail object. ADF iterators automatically manage the synchronization of the detail data objects displayed for a selected master data object. Iterator bindings simplify building user interfaces that allow scrolling and paging through collections of data and drilling-down from summary to detail information.
You display master and detail objects in forms and tables. The master-detail form can display these objects on separate pages. For example, you can display the master object in a table on one page and detail objects in a read-only form on another page.
Note:
There are some cases when the master-detail UI components that JDeveloper provides cannot provide the functionality you require. For example, you may need to bind components programatically instead of using the master-detail UI components.A master object can have many detail objects, and each detail object can in turn have its own detail objects, down to many levels of depth. If one of the detail objects in this hierarchy is dropped from the Application Navigator as a master-detail form on a page, only its immediate parent master object displays on the page. The hierarchy will not display all the way up to the topmost parent object.
If you display the detail object as a tree or tree table object, it is possible to display the entire hierarchy with multiple levels of depth, starting with the topmost master object, and traversing detail children objects at each node.
You can declaratively create pages that display master-detail data using the Data Controls panel. The Data Controls panel displays master-detail related objects in a hierarchy that mirrors the one you defined in the application module data model, where the detail objects are children of the master objects. For information about adding master-detail objects to the data model, see Section 5.6.4, "How to Enable Active Master-Detail Coordination in the Data Model."
To display master-detail objects as form or table objects, drag the detail object from the Data Controls panel and drop it on the page. Its master object is automatically created on the page.
Figure 24-3 shows two master-detail related collections in the Data Controls panel of the Fusion Order Demo application. The Products
collection is an instance of the ProductsVO
view object, and the WarehouseStockLevels
collection, which appears as a child of the Products
collection, is an instance of the WarehouseStockLevelsVO
view object.
Note:
The master-detail hierarchy displayed in the Data Controls panel does not reflect the cardinality of the relationship (that is, one-to-many, one-to-one, many-to-many). The hierarchy simply shows which collection (the master) is being use to retrieve one or more objects from another collection (the detail).The master-detail hierarchy on the Data Controls panel reflects the hierarchy defined in the application module data model, as shown in Figure 24-4. The hierarchy was established by creating a view link from the ProductsVO
view object to the WarehouseStockLevelsVO
view object. Next, an instance of the resulting detail view object, WarehouseStockLevelsVO
via ProductsToWarehouseStockLevels
, was added to the application module data model shown in Figure 24-4.
In the Fusion Order Demo application, the view link between the ProductsVO
view object and WarehouseStockLevelsVO
view object is a one-way relationship. If the view link were bidirectional and both sets of master and detail view objects were added to the application module data model, then the Data Controls panel would also display the WarehouseStockLevelsVO
collection at the same node level as the Products
collection, and the detail instance of the Products
collection as a child of the WarehouseStockLevelsVO
collection.
Tip:
By default, when you define a view link using the Create View Link wizard, the source view object is the master and the destination view object is the detail. However, if you choose to generate accessors in both the source and the destination view objects, then the master-detail relationship is bidirectional. If both sets of master-detail view objects resulting from a bidirectional view link are added to the application module data model, then instances of both sets of view objects will appear independently on the Data Controls panel.For more information about the icons displayed on the Data Controls panel, see "Section 12.3.1, "How to Use the Data Controls Panel."
You can create a master-detail browse page in a single declarative action using the Data Controls panel. All you have to do is drop the detail collection on the page and choose the type of widget you want to use.
The prebuilt master-detail widgets available from the Data Controls panel include range navigation that enables the end user to scroll through the data objects in collections. You can delete unwanted attributes by removing the text field or column from the page.
Figure 24-5 shows an example of prebuilt master-detail widget, which displays products information in a form at the top of the page and stock levels in a table at the bottom of the page. When the user clicks the Next button to scroll through the records in the master data at the top of the page, the page automatically displays the related detail data.
If you do not want to use the prebuilt master-detail widgets, you can drag and drop the master and detail objects individually from the Data Controls panel as tables and forms on a single page or on separate pages.
The Data Controls panel enables you to create both the master and detail widgets on one page with a single declarative action using prebuilt master-detail forms and tables. For information about displaying master and detail data on separate pages, see Section 24.3.4, "What You May Need to Know About Displaying Master-Detail Widgets on Separate Pages."
To create a master-detail page using the prebuilt ADF master-detail forms and tables:
From the Data Controls panel, locate the detail object, as described in Section 24.2, "Identifying Master-Detail Objects on the Data Controls Panel."
Drag and drop the detail object onto the JSF page.
Note:
If you want to create an editable master-detail form, drop the master object and the detail object separately on the page.In the context menu, choose one of the following master-detailsUI components:
ADF Master Table, Detail Form: Displays the master objects in a table and the detail objects in a read-only form under the table.
When a specific data object is selected in the master table, the first related detail data object is displayed in the form below it. The user must use the form navigation to scroll through each subsequent detail data object.
ADF Master Form, Detail Table: Displays the master objects in a read-only form and the detail objects in a read-only table under the form.
When a specific master data object is displayed in the form, the related detail data objects are displayed in a table below it.
ADF Master Form, Detail Form: Displays the master and detail objects in separate forms.
When a specific master data object is displayed in the top form, the first related detail data object is displayed in the form below it. The user must use the form navigation to scroll through each subsequent detail data object.
ADF Master Table, Detail Table: Displays the master and detail objects in separate tables.
When a specific master data object is selected in the top table, the first set of related detail data objects is displayed in the table below it.
If you want to modify the default forms or tables, see Section 22.3, "Creating a Basic Form" or Section 23.2, "Creating a Basic Table."
When you drag and drop a collection from the Data Controls panel, JDeveloper does many things for you, including adding code to the JSF page and the corresponding entries in the page definition file. For a full description of what happens and what is created when you use the Data Controls panel, see Section 12.3.1, "How to Use the Data Controls Panel."
The JSF code generated for a prebuilt master-detail widget is similar to the JSF code generated when you use the Data Controls panel to create a read-only form or table. If you are building your own master-detail widgets, you might want to consider including similar components that are automatically included in the prebuilt master-detail tables and forms.
The tables and forms in the prebuilt master-detail widgets include a panelHeader
tag that contains the fully qualified name of the data object populating the form or table. You can change this label as needed using a string or an EL expression that binds to a resource bundle.
If there is more than one data object in a collection, a form in a prebuilt master-detail widget includes four commandButton
tags for range navigation: First
, Previous
, Next
, and Last
. These range navigation buttons enable the user to scroll through the data objects in the collection. The actionListener
attribute of each button is bound to a data control operation, which performs the navigation. The execute
property used in the actionListener
binding, invokes the operation when the button is clicked. (If the form displays a single data object, JDeveloper automatically omits the range navigation components.) For more information about range navigation, see Section 22.4, "Incorporating Range Navigation into Forms."
Tip:
If you drop an ADF Master Table, Detail Form or ADF Master Table, Detail Table widget on the page, the parent tag of the detail component (for example,panelHeader
tag or table
tag) automatically has the partialTriggers
attribute set to the id
of the master component (see Section 23.4.1, "How to Create an Input Table" for more information about partial triggers). At runtime, the partialTriggers
attribute causes only the detail component to be rerendered when the user makes a selection in the master component, which is called partial rendering. When the master component is a table, ADF uses partial rendering, because the table does not need to be rerendered when the user simply makes a selection in the facet. Only the detail component needs to be rerendered to display the new data.Example 24-1 shows the page definition file created for a master-detail page that was created by dropping the WarehouseStockLevels
collection, which is a detail object under the Products
object, on the page as an ADF Master Form, Detail Table.
The executables
element defines two iterators: one for the product (the master object) and one for the WarehouseStockLevels (the detail object). The underlying view link from the master view object to the detail view object establishes the relationship between the two iterators. At runtime, the UI-aware data model and the row set iterator for the detail view object instance keep the row set of the detail view object refreshed to the correct set of rows for the current master row as that current row changes (for more information, see Section 24.3.3, "What Happens at Runtime: ADF Iterator for Master-Detail Tables and Forms").
The bindings
element defines the value bindings for the form and the table. The attribute bindings that populate the text fields in the form are defined in the attributeValues
elements. The id
attribute of the attributeValues
element contains the name of each data attribute, and the IterBinding
attribute references an iterator binding to display data from the master object in the text fields.
The attribute bindings that populate the text fields in the form are defined in the attributeValues
elements. The id
attribute of the attributeValues
element contains the name of each data attribute, and the IterBinding
attribute references an iterator binding to display data from the master object in the text fields.
The range navigation buttons in the form are bound to the action bindings defined in the action
elements. As in the attribute bindings, the IterBinding
attribute of the action binding references the iterator binding for the master object.
The table, which displays the detail data, is bound to the table binding object defined in the table
element. The IterBinding
attribute references the iterator binding for the detail object.
For more information about the elements and attributes of the page definition file, see Section A.8, "pageNamePageDef.xml."
Example 24-1 Binding Objects Defined in the Page Definition for a Master-Detail Page
<executables> <iterator Binds="Products" RangeSize="25" DataControl="StoreServiceAMDataControl" id="ProductsIterator"/> <iterator Binds="WarehouseStockLevels" RangeSize="25" DataControl="StoreServiceAMDataControl" id="WarehouseStockLevelsIterator"/> </executables> <bindings> <methodAction id="findHelpTextById" RequiresUpdateModel="true" Action="invokeMethod" MethodName="findHelpTextById" IsViewObjectMethod="false" DataControl="LookupServiceAMDataControl" InstanceName="LookupServiceAMDataControl.dataProvider" ReturnName="LookupServiceAMDataControl.methodResults. findHelpTextById_LookupServiceAMDataControl_ dataProvider_findHelpTextById_result"> <NamedData NDName="helpId" NDType="java.lang.Long" NDOption="2"/> </methodAction> <tree IterBinding="ProductsIterator" id="Products"> <nodeDefinition DefName="oracle.fodemo.storefront.store.queries.ProductsVO"> <AttrNames> <Item Value="ProductId"/> <Item Value="SupplierId"/> <Item Value="CategoryId"/> <Item Value="ProductName"/> ... <Item Value="CostPrice"/> <Item Value="DragId"/> </AttrNames> </nodeDefinition> </tree> <tree IterBinding="WarehouseStockLevelsIterator" id="WarehouseStockLevels"> <nodeDefinition DefName="oracle.fodemo.storefront.store. queries.WarehouseStockLevelsVO"> <AttrNames> <Item Value="ProductId"/> <Item Value="WarehouseId"/> ... <Item Value="ShippingClassCode"/> </AttrNames> </nodeDefinition> </tree> </bindings>
At runtime, an ADF iterator determines which row from the master table object to display in the master-detail form. When the form first displays, the first master table object row appears highlighted in the master section of the form. Detail table rows that are associated with the master row display in the detail section of the form.
As described in Section 24.3.2.2, "Binding Objects Defined in the Page Definition File," ADF iterators are associated with underlying row setIterator
objects. These iterators manage which data objects, or rows, currently display on a page. At runtime, the row set iterators manage the data displayed in the master and detail components.
Both the master and detail row set iterators listen to row set navigation events, such as the user clicking the range navigation buttons, and display the appropriate row in the UI. In the case of the default master-detail components, the row set navigation events are the command buttons on a form (First, Previous, Next, Last).
The row set iterator for the detail collection manages the synchronization of the detail data with the master data. Because of the underlying view link from the master view object to the detail view object, the detail row set iterator listens for row navigation events in both the master and detail collections. If a row set navigation event occurs in the master collection, the detail row set iterator automatically executes and returns the detail rows related to the current master row.
The default master-detail components display the master-detail data on a single page. However, using the master and detail objects on the Data Controls panel, you can also display the collections on separate pages, and still have the binding iterators manage the synchronization of the master and detail objects.
For example, in the Fusion Order Demo application, a product table and product details are displayed on the home page. However, the page could display the product table only. It could provide a button called Details. If the user clicked the Details button, the application would navigate to a new page that displays all the related details in a list. A button on the list's page would enable the user to return to the service request page.
To display master-detail objects on separate pages, create two pages, one for the master object and one for the detail object, using the individual tables or forms available from the Data Controls panel. Remember that the detail object iterator manages the synchronization of the master and detail data. Be sure to drag the appropriate detail object from the Data Controls panel when you create the page to display the detail data. For more information, see Section 24.2, "Identifying Master-Detail Objects on the Data Controls Panel."
To handle the page navigation, create an ADF task flow, and then add two view activities to it, one for the master page and one for the detail page. (See Section 14.2, "Creating a Task Flow" for information about associating a View activity with an existing JSF page). Add command buttons or links to each page, or use the default Submit button available when you create a form or table using the Data Controls panel. Each button must specify a navigation rule outcome value in the action
attribute. In the task-flow-defintion.xml
file, add a navigation rule from the master data page to the detail data page, and another rule to return from the detail data page to the master data page. The from-outcome
value in the navigation rules must match the outcome value specified in the action attribute of the buttons. For information about adding navigation between pages, see Section 14.2, "Creating a Task Flow."
In addition to tables and forms, you can also display master-detail data in hierarchical trees. The ADF Faces tree
component is used to display hierarchical data. It can display multiple root nodes that are populated by a binding on a master object. Each root node in the tree may have any number of branches, which are populated by bindings on detail objects. A tree can have multiple levels of nodes, each representing a detail object of the parent node. Each node in the tree is indented to show its level in the hierarchy.
The tree
component includes mechanisms for expanding and collapsing the tree nodes; however, it does not have focusing capability. If you need to use focusing, consider using the ADF Faces treeTable
component (for more information, see Section 24.5, "Using Tree Tables to Display Master-Detail Objects"). By default, the icon for each node in the tree is a folder; however, you can use your own icons for each level of nodes in the hierarchy.
Figure 24-6 shows an example of a tree located on the home.jspx
page of the Fusion Order Demo application. The tree displays two levels of nodes: root and branch. The root node displays parent product categories such as Media, Office, and Electronics. The branch nodes display and subcategories under each parent category, such as Hardware, Supplies, and Software under the Office parent category.
A tree consists of a hierarchy of nodes, where each subnode is a branch off a higher level node. Each node level in a databound ADF Faces tree
component is populated by a different data collection. In JDeveloper, you define a databound tree using the Edit Tree Binding dialog, which enables you to define the rules for populating each node level in the tree. There must be one rule for each node level in the hierarchy. Each rule defines the following node-level properties:
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 Section 5.6.6.2, "Programmatically Accessing a Detail Collection Using the View Link Accessor")
To create the Browse tree on the Fusion Order Demo home page shown in Figure 24-6, a view object, ParentProductCategories
was created to return a list of parent categories. Another view object, ProductCategories
was created to return subcategories of products. A view link was created from the ParentProductCategories
view object to the ProductCategories
view object, thus establishing a master-detail relationship.
To add a third-level node, for example, a list of products under each subcategory, a view link would need to exist from the ProductCategories
object to the Products
view object. For more information about creating view links, see Section 5.6.6, "How to Access the Detail Collection Using the View Link Accessor."
In the case where a branch of the tree is recursive, a single view object accompanied by a self-referential view link must be defined in the data model project. For example, in a collection defined by EmployeesView
, the root node of each branch is specified by the ManagerId
attribute and the child nodes of the same branch are the employees (also known as "direct reports") who are related to the ManagerId
. The source and destination view object named by the self-referential view link are both defined as EmployeesView
with the destination renamed to DirectReports
for clarify. For more information about creating self-referential view links, see Section 5.7.1, "How to Create a Recursive Master-Detail Hierarchy for an Entity-Based View Object."
To display master-detail objects in a tree:
Drag the master object from the Data Controls panel, and drop it onto the page. This should be the master data that will represent the root level of the tree.
In the context menu, choose Trees > ADF Tree.
JDeveloper displays the Edit Tree Binding dialog, as shown in Figure 24-7. You use the binding editor to define a rule for each level that you want to appear in the tree.
In the Root Data Source dropdown list, select the data collection that will populate the root node level. This will be the master data collection. By default, this is the same collection that you dragged from the Data Controls panel to create the tree, which was a master collection.
Tip:
If you don't see the data collection you want in the Root Data Source list, click the Add button. In the Add Data Source dialog, select a data control and an iterator name to create a new data source.Click the + icon to add the root data source you selected to the Tree Level Rules list.
In the Tree Level Rules list, select the data source you just added.
In the Accessor dropdown list, select a view link accessor attribute.
The list displays only the accessor attributes that return the detail collections for the master collection you selected. For example, if you are defining the ParentProductCategories
node level and you want to add a detail level that displays all subcategories under each parent category, you would select the accessor attribute that returns the ProductCategories
collection.
If you select <none>, the node will not expand to display any detail collections, thus ending the branch.
View link accessor attributes, which return data collections, are generated when you create a view link. The Accessor field displays all accessor attributes that return detail collections for the master collection selected in the Tree Level Rules list. For more information about view objects, view links, and view link accessors, see Section 5.6.6, "How to Access the Detail Collection Using the View Link Accessor."
Select an attribute in the Available Attributes list and move it to the Display Attributes list.
The attribute will be used to display nodes at the master level. For example, for the Parent Product Categories level, you might select the Categories
attribute.
When you are finished, the Tree Binding Editor should contain values similar to those in Figure 24-7.
After defining a rule for the master level, you must next define a second rule for the detail level that will appear under the master level in the tree.
For example, in the sample tree shown in Figure 24-6, the first rule added to the tree binding editor populates the parent category nodes (Media, Office, and Electronics). The detail level rule populates the product category nodes (for example, Hardware, Supplies, and Software under the Media parent category). '
To add a second rule, click the Add icon above the Tree Level Rules list.
A detail data source should appear automatically under the master data source, as shown in Figure 24-8.
For example, if you specified Products
as the master Root Data Source, WarehouseStockLevels
will automatically appear underneath in the Tree Level Rules list, because the two data sources share a master-detail relationship.
If you are creating a tree with a recursive master-detail hierarchy, then you only need to define a rule that specifies a data source with a self accessor. A recursive tree displays root nodes based on a single collection and displays the child nodes from the attributes of a self accessor that recursively fetches data from that collection. The recursive tree differs from a typical master-detail tree because it requires only a single rule to define the branches of the tree. A recursive data source should display the data source followed by the name of the self accessor in brackets, as shown in Figure 24-9.
For example, in a collection defined by EmployeesView
, the root node of each branch could be specified by the ManagerId
for the employee and the child nodes of the same branch are the employees who are related to the ManagerId
, as specified by the self accessor DirectReports
.
Click OK.
You can add data sources to the Tree Level Rules list to increase the number of nodes that display in the tree. The order of the remaining data sources should follow the hierarchy of the nodes you want to display in the tree.
When you drag and drop from the Data Controls panel, JDeveloper does many things for you. For a full description of what happens and what is created when you use the Data Controls panel, see Section 12.3.1, "How to Use the Data Controls Panel."
When you create a databound tree using the Data Controls panel, JDeveloper adds binding objects to the page definition file, and it also adds the tree tag to the JSF Page. The resulting UI component is fully functional and does not require any further modification.
Example 24-2 shows the code generated in a JSF page when you use the Data Controls panel to create a tree. This sample tree displays two levels of nodes: parent product categories and product categories. The ParentProductCategories
collection was used to populate the root node.
Example 24-2 Code Generated in the JSF Page for a Databound Tree
<af:tree id="productCategoriesTree" contentDelivery="immediate" selectionListener="#{homePageBean. productCategoriesTreeSelectionListener}" rowSelection="single" value="#{bindings.ParentProductCategories.treeModel}" var="node" initiallyExpanded="true"> <f:facet name="nodeStamp"> <af:panelGroupLayout> <af:outputText rendered="#{node.ParentCategoryId eq null}" value="#{node.CategoryName}" inlineStyle="color:#FF8000;font-weight:bold;"/> <af:outputText rendered="#{node.ParentCategoryId ne null}" value="#{node.CategoryName}"/> </af:panelGroupLayout> </f:facet> </af:tree>
By default, the af:tree
tag is created inside a form. The value
attribute of the tree
tag contains an EL expression that binds the tree
component to the ParentProductCategories
tree binding object in the page definition file. The treeModel
property in the binding expression refers to an ADF class that defines how the tree
hierarchy is displayed, based on the underlying data model. The var
attribute provides access to the current node.
In the f:facet
tag, the nodeStamp
facet is used to display the data for each node. Instead of having a component for each node, the tree
repeatedly renders the nodeStamp
facet, similar to the way rows are rendered for the ADF Faces table component.
The ADF Faces tree
component uses an instance of the oracle.adf.view.faces.model.PathSet
class to display expanded nodes. This instance is stored as the treeState
attribute on the component. You may use this instance to programmatically control the expanded or collapsed state of an element in the hierarchy. Any element contained by the PathSet
instance is deemed expanded. All other elements are collapsed.
Example 24-3 shows the binding objects defined in the page definition file for the ADF databound tree.
Example 24-3 Binding Objects Defined in the Page Definition File for a Databound Tree
<executables> <iterator Binds="ParentProductCategories" RangeSize="25" DataControl="StoreServiceAMDataControl" id="ParentProductCategoriesIterator"/> </executables> <bindings> <tree IterBinding="ParentProductCategoriesIterator" id="ParentProductCategories"> <nodeDefinition DefName="oracle.fodemo.storefront.store.queries.ProductCategoriesVO"> <AttrNames> <Item Value="CategoryId"/> </AttrNames> <Accessors> <Item Value="ProductCategoriesVO"/> <Item Value="ParentCategoryIdProductCategoriesVO"/> </Accessors> </nodeDefinition> </tree> </bindings>
The page definition file contains the rule information defined in the Tree Binding Editor. In the executables
element, notice that although the tree displays two levels of nodes, only one iterator binding object is needed. This iterator iterates over the master collection, which populates the root nodes of the tree. The accessor you specified in the node rules returns the detail data for each branch node.
The tree
element is the value binding for all the attributes displayed in the tree. The iterBinding
attribute of the tree
element references the iterator binding that populates the data in the tree. The AttrNames
element within the tree
element defines binding objects for all the attributes in the master collection. However, the attributes that you select to appear in the tree are defined in the AttrNames
elements within the nodeDefinition
elements.
The nodeDefinition
elements define the rules for populating the nodes of the tree. There is one nodeDefinition
element for each node, and each one contains the following attributes and subelements:
DefName
: An attribute that contains the fully qualified name of the data collection that will be used to populate the node.
id
: An attribute that defines the name of the node.
AttrNames
: A subelement that defines the attributes that will be displayed in the node at runtime.
Accessors
: A subelement that defines the accessor attribute that returns the next branch of the tree.
The order of the nodeDefintion
elements within the page definition file defines the order or level of the nodes in the tree, were the first nodeDefinition
element defines the root node. Each subsequent nodeDefinition
element defines a sub-node of the one before it.
For more information about the elements and attributes of the page definition file, see Appendix A, "pageNamePageDef.xml."
Tree
components use org.apache.myfaces.trinidad.model.TreeModel
to access data. This class extends CollectionModel
, which is used by the ADF Faces table
component to access data. For more information about the TreeModel
class, refer to the ADF Faces Javadoc.
When a page with a tree
is displayed, the iterator binding on the tree populates the root nodes. When a user collapses or expands a node to display or hide its branches, a DisclosureEvent
event is sent. The isExpanded
method on this event determines whether the user is expanding or collapsing the node. The DisclosureEvent
event has an associated listener.
The DisclosureListener
attribute on the tree
is bound to the accessor attribute specified in the node rule defined in the page definition file. This accessor attribute is invoked in response to the DisclosureEvent
event; in other words, whenever a user expands the node the accessor attribute populates the branch nodes.
Use the ADF Faces treeTable
component to display a hierarchy of master-detail collections in a table. The advantage of using a treeTable
component rather than a tree
component is that the treeTable
component provides a mechanism that enables users to focus the view on a particular node in the tree.
For example, you can create a tree table that displays three levels of nodes: countries, states or provinces, and cities. Each root node represents an individual country. The branches off the root nodes display the state or provinces in the country. Each state or province node branches to display the cities contained in it.
As with trees, to create a tree table with multiple nodes, it is necessary create view links between the view objects. The view links establish the master-detail relationships For example, to create a tree table with three levels of country, state, and city, it was necessary to create view links from the CountryCodes
object to the StatesandProvinces
view object, and another view link from the StatesandProvinces
view object to the Cities
view object. For more information about creating view links, see Section 5.6, "Working with Multiple Tables in a Master-Detail Hierarchy."
A databound ADF Faces treeTable
displays one root node at a time, but provides navigation for scrolling through the different root nodes. Each root node can display any number of branch nodes. Every node is displayed in a separate row of the table, and each row provides a focusing mechanism in the leftmost column.
You can edit the following treeTable
component properties in the Property Inspector:
Range navigation: The user can click the Previous and Next navigation buttons to scroll through the root nodes.
List navigation: The list navigation, which is located between the Previous and Next buttons, enables the user to navigate to a specific root node in the data collection using a selection list.
Node expanding and collapsing mechanism: The user can open or close each node individually or use the Expand All or Collapse All command links. By default, the icon for opening and closing the individual nodes is an arrowhead with a plus or minus sign. You can also use a custom icon of your choosing.
Focusing mechanism: When the user clicks on the focusing icon (which is displayed in the leftmost column) next to a node, the page is redisplayed showing only that node and its branches. A navigation link is provided to enable the user to return to the parent node.
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.
When you drag and drop from the Data Controls panel, JDeveloper does many things for you. For a full description of what happens and what is created when you use the Data Controls panel, see Section 12.3.1, "How to Use the Data Controls Panel."
When you create a databound tree table using the Data Controls panel, JDeveloper adds binding objects to the page definition file, and it also adds the treeTable
tag to the JSF Page. The resulting UI component is fully functional and does not require any further modification.
Example 24-4 shows the code generated in a JSF page when you use the Data Controls panel to create a tree table. This sample tree table displays two levels of nodes: products and stock levels.
By default, the treeTable
tag is created inside a form. The value
attribute of the tree
table tag contains an EL expression that binds the tree
component to the binding object that will populate it with data. The treeModel
property refers to an ADF class that defines how the tree hierarchy is displayed, based on the underlying data model. The var
attribute provides access to the current node.
Example 24-4 Code Generated in the JSF Page for a Databound ADF Faces Tree Table
<af:form> <af:treeTable value="#{bindings.Products.treeModel}" var="node" selectionListener="#{bindings.Products.treeModel.makeCurrent}" rowSelection="single"> <f:facet name="nodeStamp"> <af:column customizationId="column1"> <af:outputText value="#{node}"/> </af:column> </f:facet> <f:facet name="pathStamp"> <af:outputText value="#{node}"/> </f:facet> </af:treeTable> </af:form>
In the facet
tag, the nodeStamp
facet is used to display the data for each node. Instead of having a component for each node, the tree repeatedly renders the nodeStamp
facet, similar to the way rows are rendered for the ADF Faces table
component. The pathStamp
facet renders the column and the path links above the table that enable the user to return to the parent node after focusing on a detail node.
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.
You can expand a node binding in the page definition editor to view the page's node Definition
elements. These are the same tree binding rules that you can configure in the tree binding dialog.
For each node definition (rule), you can specify an optional TargetIterator
property. Its value is an EL expression that is evaluated at runtime when the user selects a row in the tree. The EL expression evaluates an iterator binding in the current binding container. The iterator binding's view row key attributes match (in order, number, and data type) the view row key of the iterator from which the nodeDefinition
type's rows are retrieved for the tree.
At runtime, when the tree control receives a selectionChanged
event, it passes in the list of keys for each level of the tree. These keys uniquely identify the selected node.
The tree binding starts at the top of the tree. For each tree level whose key is present in the Currently Selected Tree Node Keys
list, if there is a TargetIterator
property configured for that nodeDefinition
, the tree binding performs a setCurrentRowWithKey()
operation on the selected target iterator. It uses the key from the appropriate level of the Currently Selected Tree Node Key
s list.
For example, you may have created DeptEO
and EmpEO
entity objects, and created view links based on these entity objects. The view link accessor in the DeptVO
object that returns the linked collection of employees in that department is named EmployeesInDepartment
. The application module will have a DepartmentsTree
view object instance of type DeptVO
. It will also have an EditDepartment
view object instance of type DeptVO
, and a view link for the EditEmployees
view object instance of type EmpVO
.
Drag the DepartmentsTree data collection from the Data Controls panel onto the page and choose Create > Trees > ADF Tree.
Configure tree binding rules to navigate the EmployeesInDepartment
view link accessor attribute.
This will access the children employee rows of the current department row.
Drag the EditEmployees detail view object instance to the page, and choose Create > Master-Detail > ADF Master Form, Detail Form.
This creates a form to edit a department and a form to edit an employee in that department.
For the DeptVO
node definition of the tree binding, configure the TargetIterator
property to be #{bindings.EditDepartmentIterator}.
For the EmpVO
node definition of the tree binding, configure the TargetIterator
property to be #{bindings.EditEmployeesIterator}
.
When you run the master-detail form, clicking on an employee in any department in the tree will first set the current department row in the target iterator for the department of that selected employee. Then it will set the current employee row in the target iterator for the selected employee.
There may be cases when you need to determine which node in a tree or tree table has been selected in order to handle some processing in your application. For example, on the home page of the StoreFront module, when a user selects a category node in the Browse tree, a selection event is fired. The listener associated with this event needs to determine the product category of the node selected, and then to return all products whose category attribute matches that value.
To programmatically use selection events, you need to create a listener in a managed bean that will handle the selection event and perform the needed logic. You then need to bind the selectionListener
attribute of the tree or table to that listener.
To use selection events with trees and tables:
If one does not already exist, create a managed bean to contain the needed listener. For more information about creating and using managed beans, see Section 20.4, "Using a Managed Bean in a Fusion Web Application."
Create a listener method on the managed bean. For more information about creating listener methods, see the "Using ADF Faces Server Events" section of the Oracle Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework. Your listener should do the following:
Access the component using the event source. Example 24-5 shows how the productCategoriesTreeSelectionListener
method on the HomeBean
managed bean accesses the tree that launched the selection event.
Example 24-5 Getting the Source of an Event
public void productCategoriesTreeSelectionListener(SelectionEvent evt) { RichTree tree = (RichTree)evt.getSource();
For more information about finding the event source component, see the "How to Return the Original Source of the Event" section of the Oracle Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework.
Access the tree model to get the value of the model, use the RowKeySet
object to get the currently selected node, and then set that as the current row on the model, as shown in Example 24-6. For more information about RowKeySet
objects, see Section 24.6.2, "What Happens at Runtime: RowKeySet Objects and SelectionEvent Events."
You can now add logic to execute against the currently selected row. For example, the productCategoriesTreeSelectionListener
method uses the value binding of the selected row to determine the category ID, and then uses that value as the parameter for another method that when executed, returns all products with that category ID, as shown in Example 24-7.
Example 24-7 Returning Objects that Match a Given Attribute Value
JUCtrlValueBinding nodeBinding = (JUCtrlValueBinding)model.getRowData(); Number catId = (Number)nodeBinding.getAttribute("CategoryId"); _selectedCategory = (String)nodeBinding.getAttribute("CategoryName"); OperationBinding ob = ADFUtils.findOperation("ProductsByCategoriesExecuteWithParams"); ob.getParamsMap().put("category", catId); ob.execute();
On the associated JSF page, select the tree or table component. In the Property Inspector, expand the Behavior section and set the value of the SelectionListener
attribute to the listener method just created. You can use the Edit option from the dropdown method to declaratively select the bean and the method.
Whenever a user selects a node in a tree (or a row in a table), the component triggers selection events. A selectionEvent
event reports which rows were just deselected and which rows were just selected. The current selection, that is, the selected row or rows, is managed by the RowKeySet
object, which keeps track of all currently selected nodes by adding and deleting the associated key for the row into or out of the key set. When a user selects a new node, and the tree or table is configured for single selection, then the previously selected key is discarded and the newly selected key is added. If the tree or table is configured for multiple selection, then the newly selected keys are added to the set, and the previously selected keys may or may not be discarded, based on how the nodes were selected. For example, if the user pressed the CTRL
key, then the newly selected nodes would be added to the current set.