ADF Faces Tree Component Example

There are a number of questions on OTN regarding the Tree Component. We hope this post will be helpful in answering some of them.

You can download the sample application from here. The application is developed in JDeveloper and uses the HR schema.

The sample application contains four simple examples on how to use the ADF Faces tree component;

1) How to set the focus of the tree to the node that is clicked.

2) How to detect the type of the node that is clicked.

3) How to use the polymorphic restriction functionality.

4) How to change the tree state in a managed bean.

Sample Application

The application contains a tree that is showing the regions, countries and locations in a hierarchical order.

Polymorphic Restriction
This hierarchy is altered only for the Americas region to showcase the polymorphic restriction capability of the tree binding. Polymorphic Restriction is used if the nodes from the same Data Collection Definition should have different child nodes. In the sample tree, Americas is divided into two "subregions"; North America and South America. The countries in the Americas region appear under the appropriate subregion node.

To achieve this, the necessary viewobjects are created using JDeveloper's Business Components Generation Wizard. Since the HR schema does not have the notion of a subregion, a viewobject is created for subregions using the following query;

The CountriesView viewobject is edited so that the countries in Americas can be linked to either North or South America.

Similarly, a new column named hassubregion_yn is added to the RegionsView SQL query to indicate which regions have a subregion. (At a later stage this column is going to be used in the polymorphic restriction section as the discriminator column.)

The viewlinks between the Regions-SubRegions and SubRegions-Countries are created. The JDeveloper Business Components Generator wizard automatically creates instances in the application module for the viewobjects it generates.

For the tree to run successfully, only the RegionsView1 instance is required. The framework automatically creates the viewobjects and the iterators it uses to retrieve the child nodes. In other words, even if your page definition XML has only one iterator (RegionsView1Iterator) and the Application Module contains only viewobject instance (RegionsView1) the tree is going to function properly. However, the tree editor cannot be used to maintain the rules for the tree if the application module does not contain any instances of the CountriesView, LocationsView and the SubRegionsView. This is because the editor populates its list for Data Collection Definition using the names of the viewobjects in the application module. If the tree binding is going to be maintained by editing the page definition XML, then the additional viewobject instances are not needed.

Using Tree Binding Editor to create a polymorphic restriction
In the editor, two rules are created to branch from a Region node to a child node. In both rules the Data Collection Definition is selected as the RegionsView. In rule 1;
  • the CountriesView is selected in the Branch Rule Accessor field.
  • The polymorphic definition is set to HasSubRegionYn=N.

In plain english this means; "Each region node that has no subregions branches to Countries".
In rule 2;
  • the SubRegionsView is selected in the Branch Rule Accessor field.
  • The polymorphic definition is set to HasSubRegionYn=Y

In plain English this means; "Each region node that has a subregion branches to SubRegions".This completes the polymorphic restriction example in the sample application.

Changing the Tree State using a managed bean
The need to customize the tree state of an ADF Faces Tree Component is not uncommon. This technique can be applied to various areas such as; opening the root node at the start of the application, adjusting the tree state after an insert, delete or edit operation.

In the sample application, every node in the tree expands if it is clicked. If the clicked node is already expanded, then the node is collapsed. This is done by altering the tree state in a managed bean.

The following text describes the steps to achieve this effect in the sample application;

In the JSP page, a commandLink is added to the nodeStamp facet with an action listener bound to the clickTree method in MyBean. Inside the commandLink a SetActionListener assigns the RowKey of the clicked node to the clickedNodeRowKey property.

<afh:tableLayout cellSpacing="5">
<afh:rowLayout width="100%">
<afh:cellFormat valign="top" height="700"
inlineStyle="padding-right: 15px; border-right: 2px solid #3A6EA5;">
<af:tree binding="#{MyBean.tree}"
value="#{bindings.RegionsView1.treeModel}" var="node"
<f:facet name="nodeStamp">
<af:commandLink text="#{node}"
<af:setActionListener from="#{MyBean.tree.rowKey}"
<afh:cellFormat halign="left" valign="top">
<af:outputText value="#{MyBean.clickedNodeType}"/>
Inside the clickTree method, doTreeState() method is called, which alters the tree state and expands or collapses a clicked tree node depending on its current state.
public void doTreeState() {
PathSet treePathSet = this.getTree().getTreeState();
List<List> clickedNodePath = (List<List>)clickedNodeRowKey;
Iterator iter = getTree().getTreeState().getKeySet().iterator();
boolean addCurrentNodePathToTreeState=true;
while (iter.hasNext()) {
List openNodePath = (List);
if(openNodePath.equals(this.clickedNodeRowKey)) {
if(addCurrentNodePathToTreeState) {
This completes the changing of the tree state using a managed bean.

Final Remarks
The sample application uses a middle tier centric approach for the tree development. The same JSP Page could be developed using a recursive database view. In the near future, we will add a post to the blog that demonstrates this approach.

The Tree Binding has a limitation in which there cannot be a polymorphic restricted and a non-restricted rule pointing to the same data collection definition. The Editor displays a warning message and does not let the developer create the second rule, which violates the limitation. However, the Editor has a bug. If there are multiple rules with polymorphic restriction pointing to the same data collection definition, unchecking the polymorphic restriction checkbox and clicking the “modify current rule” button on any of them, should be an illegal operation because it would create a non-restricted rule while polymorphic restricted rules exist in the binding. In the editor the described operation does not warn the user and gives the impression it succeeds even though internally JDeveloper does not modify the page definition XML.

Make sure you define a rule for each viewobject you select in Branch Rule Accessor field of the Tree Binding Editor. In other words, ensure that all children that a parent data collection definition branches to, have a data collection definition themselves. In the sample application the LocationsView is at the bottom of the hierarchy. This does not mean that it does not need a rule. It must have a rule that branches nowhere. (In the page definition XML a rule is called a nodeDefinition which better explains what the object really is.) If such a mistake is made the framework throws an oracle.jbo.NoDefException: JBO-25058 exception with a misleading error message.

Yalım K. Gerger


senthil said…

This segment was was very useful. but how do i select the root node at the start of my application as you have mentioned. i.e. without any mouse click events, the root node should be expanded and the child nodes should be selected underneath.
arco said…
Yes. Nice post and blog.
Dancing Bear said…
This looks like it cold help me out a bit .... Could you please let me know where I can get a copy of your
harsh kumar said…
Hi I am using tree table to display the data.The problem I am getting is the folder icon is not coming for collapse and extend instead it comes simple arrow like this ">". Can u tell me how to do this.

Popular posts from this blog

Wrapping PL/SQL Source Code and a Strange Bug (PLS-00753)

An ADF Faces ProgressIndicator Example for File Upload

JavaScript DecimalFormat