As you may have gathered from some recent posts, we are in the process of developing an ADF Faces/ADF Business Components application in a project for one of the largest cities in The Netherlands. We have a requirement for the tree – one of the key navigation components in this application: it should be able to show child nodes from various data sources (ViewObjects) under one parent and it should show child node labels under the parent before showing the children. The latter means that under the Department node we do not want to immediately get all Employee children, but instead first have the label Employees under which all Employee children are listed.
I want to achieve something like:
However, the ADF Faces Tree Component is based on the FacesCtrlHierBinding and the FacesModel classes when we use the ADF Binding framework as an intermediary between the Tree and the Model. And this ADF Binding Model does not allow for child nodes from multiple ViewObjects. And child node labels are not catered for – or at least not without a workaround. This article obviously will discuss that workaround.
If we cannot have the ADF Model Tree component come to our ViewObjects, we will have to be flexible on our end, I am afraid. So the crux of the solution is the development of a set of ViewObjects that provide the data in our tree. Most specifically:
- we will have one ViewObject for each level in the tree (HrmTreeFirstLevelView, HrmTreeSecondLevelView, …)
- each tree level ViewObject will return the same five attributes: NodeKey, NodeType, NodeLabel (what is displayed in the tree component), ParentKey and ParentType (the latter two attributes required to link child nodes to their parents)
- we will have ViewLinks between each pair of ViewObjects, from FirstLevel to SecondLevel, from SecondLevel to ThirdLevel and so on
- the application module’s data model will have a nested hierarchy of all TreeLevel views, linked by the view links
- in our JSF JSP page we will set up a Tree Component based on the ViewObject(Usage) hierarchy
ViewObjects for the tree
As stated before, we need to create a View Object for each level in the tree. We need to carefully design the tree and know at each level which nodes we want to have, both static and (dynamic) data-driven. For each node (type) we need to define its key and type as well as its link to the parent (also through key and type). Finally we determine the label to be displayed to the end user. All our ViewObjects will be read only, based on a custom SQL statement.
The first level in the tree typically contains static node labels, indicating the various categories of nodes available in the tree. The HrmTreeFirstLevelView is based on the following SQL Statement:
select node_key
, node_type
, node_label
, parent_key
, parent_type
from ( select 1 node_key
, 'root' node_type
, 'Departments' node_label
, null parent_key
, null parent_type
from dual
UNION ALL
select 2 node_key
, 'root' node_type
, 'Employees' node_label
, null parent_key
, null parent_type
from dual
UNION ALL
select 3 node_key
, 'root' node_type
, 'Locations' node_label
, null parent_key
, null parent_type
from dual
)
The second level tree adds the first dynamic, data driven nodes. Under the First Level Employees Node, we want to have all Employees in the EMP table. Under the Departments node we likewise want to see all Departments in DEPT and under Locations we want to get a listing of all distinct Locations values in DEPT. We also need to indicate for each of these nodes how they link to their Parents from the HrmTreeFirstLevelView. The SQL Statement for this ViewObject is now:
select node_key
, node_type
, node_label
, parent_key
, parent_type
from ( select empno node_key
, 'emp' node_type
, ename node_label
, 2 parent_key
, 'root' parent_type
from emp
UNION ALL
select deptno node_key
, 'dept' node_type
, dname node_label
, 1 parent_key
, 'root' parent_type
from dept
UNION ALL
select deptno node_key
, 'loc' node_type
, loc node_label
, 3 parent_key
, 'root' parent_type
from dept
)
The Third Level adds labels for Salesmen and Clerks per Department and Subordinates under Employees:
select node_key
, node_type
, node_label
, parent_key
, parent_type
from ( select empno node_key
, 'subLabel' node_type
, 'Subordinates' node_label
, empno parent_key
, 'emp' parent_type
from emp
UNION ALL
select deptno node_key
, 'salesmenLabel' node_type
, 'Salesmen' node_label
, deptno parent_key
, 'dept' parent_type
from dept
UNION ALL
select deptno node_key
, 'clerksLabel' node_type
, 'Clerks' node_label
, deptno parent_key
, 'dept' parent_type
from dept
)
The last level discussed in this article will show those Salesmen, Clerks and Subordinates, using the following SQL Statement:
select node_key
, node_type
, node_label
, parent_key
, parent_type
from ( select empno node_key
, 'emp' node_type
, ename node_label
, mgr parent_key
, 'subLabel' parent_type
from emp
UNION ALL
select empno node_key
, 'salesmenLabel' node_type
, ename node_label
, deptno parent_key
, 'salesmenLabel' parent_type
from emp
where job ='SALESMAN'
UNION ALL
select empno node_key
, 'emp' node_type
, ename node_label
, deptno parent_key
, 'clerksLabel' parent_type
from emp
where job = 'CLERK'
)
note: the NodeKey and NodeType attributes are both Key Attributes for these ViewObjects. Also note that in this article I quit with these four levels but that is not because of any sort of limitation – you can continue for pretty much as long as you like. Finally: I did not do it in this example, but there is no reason why you could not mix Static Labels and Dynamic Data in the same level ViewObject.
The ViewLinks to tie the tree levels together
The ADF Tree is driven by "rules" that hinge on ViewObjects (DataControl Collections) tied together throug
h ViewLi
nks. Each level in our tree hierarchy is tied to the next through a ViewLink. And each of these ViewLinks is constructed in the same manner:
The higher level is the Source, the lower (child) level the target. The join is on NodeKey to ParentKey and NodeType to ParentType. I have used a naming convention like HrmTreeFirstSecondViewLink, HrmTreeSecondThirdViewLink etc. for clarity.
Creating the Application Module’s Data Model
All ViewObjects we want to use to base our tree on must be included in the Data Model for the Application Module. In fact, they must be nested in that data model in the same way we want to nest them in the tree in the user interface:
Note that this is an excellent moment to the tree model we have now set up, using the ADF BC ApplicationModule Tester , from the RMB menu on the Application Module.
Creating the JSF page with the ADF Faces Tree Component
Well, all that is left to do is creating the page we so much desired. Simply create a new JSF JSP page, accept all defaults or change them as you see fit. From the ADF Data Control Palette, drag the AppModule.HrmFirstLevelView1 Collection to your page. In the UI Widget dialog, select ADF Tree. Subsequently, set up the tree binding rules in the following way:
Each tree level will have a rule. Select the Data Collection for the current level, select NodeLabel as Display Attribute and select the next (lower) level’s ViewObject as Branch Rule Accessor. Press the Add New Rule button to save this rule. Repeat this process for every level in the tree. For the lowest level there obviously is no Branch Rule Accessor to create – as this specifies the collection providing the child nodes which of course the lowest level does not have.
Now you can run the application. You should see our much coveted tree as displayed in the beginning of this article. Compliments to Jan R.!
Great article Lucas
Thank you Lucas .
This article is awesome . It’s very well written and self explanatory.
Cheers,
Reena
I got the answer – the data types should also match. In my case 1st and 2d level node key and parent key were compatible but 3rd and 4th were not. I changed all these types to String from Integer wherever they were Integer’s and it worked.
Hi, Thatnks for this very useful article. I went step by step as described in the article and was able to see my tree based on my test tables different than DEPT, EMP etc. When I ran the application, its showing me just two levels and when i try to expand to third level it takes few seconds (and shows green bars at the bottom) and then nothing happens. Any guesses why?
Thanks, fore this article but with jdeveloper 11g did i do the same thing to have a tree of folder in wich every folder has many other folders
Lucas,
Great article!
Ric
Principal Product Manager
Oracle JDeveloper & ADF
Well, the action you want to perform when the node is selected is something you specify yourself in the facet for the tree node. Since the node object not only has a label but also has properties like node key and type and parent key and type, you can bind the action property of the command link to a method on a managed bean and have this method figure out which page to navigate to.
An example of this behavior is described in the article Generating an Advanced ADF Faces Tree based application with JHeadstart 10.1.3.
Although there I have used the JHeadstart run time facilities, the idea basically is the same.
The facet for the second level in the tree – and illustrative for all levels in the tree:
<f:facet name=”HrmTreeSecondLevelView1Node”>
<af:commandLink text=”#{node.NodeLabel}”
immediate=”true” onclick=”return alertForChanges()”
action=”#{TreeHelper.action}”
>
<af:setActionListener from=”#{node}”
to=”#{TreeHelper.node}”/>
It sets the currently selected node on the node property in TreeHelper bean. This bean exposes properties like nodeKey, nodeType, parentKey and parentType – the values for these properties are retrieved from the selected node. The action attribute of the commandLink is bound to the action() method on the TreeHelper bean. This method checks out which node is selected and then determines which outcome to return. This outcome obviously corresponds with various navigation paths in the faces-config.xml file.
Note: each node type will have its own Edit Page – with the tree included in both the page (via a region element, so node copying of the tree itself) and its PageDefinition.
I hope this helps.
Thank you for this article, it’s very useful
but how can when i click on lowest node to open the record of this node from another view obj if the user want to edit or show the detail of this node
thanks to everyone on AMIS