Friday 29 July 2011

My GO at creating a Menu Tree in ADF.

My steps:
  1. I created a SQL based View object called: MenuNodeVO.
  2. I created a View Object Link in order to setup a hierarchy that the ADF Tree can use.
  3. I created a root node View Criteria for MenuNodeVO to make it possible for only root nodes to be returned for the root nodes in the tree.
  4. I dragged and dropped my parent View Object from the Data Control to my page as an ADF Tree.
  5. I created a binding for the RichTree component in the page's backing bean.
  6. I implemented code to set the bind parameters on the view objects involved in the tree hierarchy. 
 1. I created a SQL based View object called: MenuNodeVO
This MenuNodeVO makes use of a hierarchical SQL query as such:
select id,
       parent_id,
       name,
       action,
       menu_type
from nodes
connect by prior id = parent_id
start with parent_id = -1
...(where 'nodes' denotes a table/select-statement containing all possible menuitems)

NB! After creation of MenuNodeVO set the key attribute for the view object. (i.e. id)

ALSO, I had bind parameters as part of the query amounting to 'nodes' in the query stated above and hence these bind parameters had to be set programmatically in order for the tree component to show up with the nodes and not be empty or break! So, be sure to set these bind parameters in the backing bean of your .jspx page.

Here's how to do it!

2. I created a View Link in order to setup a hierarchy that the ADF Tree can use.
There are a lot of examples out there which makes use of a different view object for each level in the tree. But, in order for the tree we're planning to create to be truly recursive and go from 1..n levels, one actually needs to use the same View Object for each level in the tree...I think it makes sense.
So, that's what I did. I created a View Link linking my MenuNodeVO to itself using id-to-parent_id as the source to destination view object attributes. Another important thing is to make sure that you specify the child view object accessor name as part of the View Link creation, as you might need it later on (In my case I did). I called it something like 'MenuChildNodes' as the name for the destination view object accessor.


3. I created a root node View Criteria for MenuNodeVO to make it possible for only root nodes to be returned for the root nodes in the tree.
This simply involved creating a View Criteria as you would usually do and adding a group item as criteria which specifies
that the parent_id should be equal to whatever the null parent id would be. (i.e parent_id = -1)
In other words, the criteria should ensure that only menu items with null parent ids should be returned by the MenuNodeVO execute query.
I named the criteria: "RootMenuNodeVOCriteria"

4. I dragged and dropped my parent View Object from the Data Control to my page as an ADF Tree.
Drag and drop is drag and drop. Nothing more to be said about that - LOL.
On the Edit Tree Binding Dialog (which appears when you drag and drop) however, you have to make sure of the following:

  • The parent node View Object iterator should be selected as your Root Data Source.
  • You should only have one Tree Level Rule specified as MenuNodeVO, with the destination child View Object accessor name in parenthesis next to it [i.e com.model.vo.MenuNodeVO(<MenuChildNodesVO>) ]
  • As usual make sure that you pick the display attributes for the Tree as you require.
5. I created a binding for the RichTree component in the page's backing bean.
The following are important:

  • You go to the binding property in the Property Inspector in JDeveloper while your RichTree component is selected.
  •  You click the down arrow next to the property and then 'Edit'.
  •  Then you select your managed bean and the property in the 'Edit Property: Binding' dialog as shown below:

6. I implemented code to set the bind parameters on the view objects involved in the tree hierarchy.
For completeness sake I've provided the getter and setter for the RichTree property binding as I've implemented in my backing bean:

public void setMenuTree(RichTree menuTree) {
    DCIteratorBinding iter = ADFUtils.findIterator("ParentNodeIteratorName");
    ViewObject parentVO = iter.getViewObject();
    parentVO.ensureVariableManager().setVariableValue("BindVariableName", "bindVarValue");

    ViewCriteria vc = parentVO.getViewCriteriaManager().getViewCriteria("RootMenuVOCriteriaName");
    vc.ensureVariableManager().setVariableValue("BindVariableName", "bindVarValue");
    parentVO.applyViewCriteria(vc, false) /* do not append the view criteria */;

    ViewObject childVO = ADFUtils.getChildViewObjectFromParent(parentVO, "ChildNodeVOAccessorName");
    childVO.ensureVariableManager().setVariableValue("BindVariableName", "bindVarValue");

    // then only set reference to given RichTree
    this.menuTree = menuTree;
}

public RichTree getMenuTree() {
    return menuTree;
}

2 comments: