I want to share today, how we are using Tree Table components in Oracle ADF. Sure, you can implement Tree or Tree Table just by reading Oracle JDeveloper 11g documentation. However, I will try aggregate different information and to put all pieces together, in order to help those developers who are just starting to use Tree components and are curious how things work. My today post is based on information from Frank Nimphius article available on ADF Code Corner - How-to access the selected row data in a TreeTable or Tree.
Download sample application developed in JDeveloper 11g R1 PS1 - TreeComponents.zip. In this sample I'm using two Tree Table components, second is dependent on first. Dependency could easily work through View Link Master-Detail relationship, but I decided to make use case a bit more complex and to filter second Tree Table from Selection Listener method. Also, I decided to include editable fields into both Tree Table components.
First Tree Table represents three level Master-Detail relationship between Regions, Countries and Locations. Second Tree Table is Master -Detail between Departments and Employees:
Its worth to mention, that Departments VO contains Bind Variable and Where clause, this allows me to filter second Tree Table from first Tree Table Selection Listener method:
On the layout side in ViewController, I have used Panel Dashboard (new component in JDeveloper 11g) - it allows to align your panels with Tree Table components in very easy and elegant way:
When you decide to create Tree or Tree Table, you should drag and drop from Data Control only Master VO. From a wizard you can add Tree Levels (VO details) and specify attributes to be shown on each level:
When Tree Table will be generated, if you want to have multiple columns, you should add Column components manually and define output/input components manually. Make sure you are assigning correct values from node binding (see my sample application):
Second Tree Table is refreshed based on selection changes in first Tree Table, this means we should declare Partial Trigger dependency:
We override default Selection Listener on first Tree Table in order to perform filtering on second Tree Table component:
In Selection Listener I'm using Java code from Frank Nimphius article mentioned above. I'm accessing currently selected row and if this row belongs to third level (Locations), I'm filtering second Tree Table:
On runtime you can see how nicely Panel Dashboard allocates two Tree Table components in Panel Boxes:
Expanded Tree Table view, with editable columns:
Download sample application developed in JDeveloper 11g R1 PS1 - TreeComponents.zip. In this sample I'm using two Tree Table components, second is dependent on first. Dependency could easily work through View Link Master-Detail relationship, but I decided to make use case a bit more complex and to filter second Tree Table from Selection Listener method. Also, I decided to include editable fields into both Tree Table components.
First Tree Table represents three level Master-Detail relationship between Regions, Countries and Locations. Second Tree Table is Master -Detail between Departments and Employees:
Its worth to mention, that Departments VO contains Bind Variable and Where clause, this allows me to filter second Tree Table from first Tree Table Selection Listener method:
On the layout side in ViewController, I have used Panel Dashboard (new component in JDeveloper 11g) - it allows to align your panels with Tree Table components in very easy and elegant way:
When you decide to create Tree or Tree Table, you should drag and drop from Data Control only Master VO. From a wizard you can add Tree Levels (VO details) and specify attributes to be shown on each level:
When Tree Table will be generated, if you want to have multiple columns, you should add Column components manually and define output/input components manually. Make sure you are assigning correct values from node binding (see my sample application):
Second Tree Table is refreshed based on selection changes in first Tree Table, this means we should declare Partial Trigger dependency:
We override default Selection Listener on first Tree Table in order to perform filtering on second Tree Table component:
In Selection Listener I'm using Java code from Frank Nimphius article mentioned above. I'm accessing currently selected row and if this row belongs to third level (Locations), I'm filtering second Tree Table:
On runtime you can see how nicely Panel Dashboard allocates two Tree Table components in Panel Boxes:
Expanded Tree Table view, with editable columns:
Tree table component will not use the detail instances added in the data model
ReplyDeleterather it uses the view link accessor driven rowsets to show up children.
So you can remove all the detail instances on a view object which tree model is based on as they get executed unncessarly when the currency is set on master.
Hello,
ReplyDeleteI have tried this before, if I will remove them, I will not be able to declare through #{node} binding and tree rendering will fail.
Regards,
Andrejus
Hi there,
ReplyDeleteWhat about re-rendering the tree after a commit. I've just started with ADF and when I insert a new element to the tree if it is a root node the tree does not render to show the included node (it works fine for children nodes though).
Any hints?
Regards,
Luppi
hi mr. Andrejus
ReplyDeletevery efficient task , but you did not mention " executeWithParams" action and how you add it , or
can you recommend docs to read about it
Hi,
ReplyDeleteExecuteWithParams is standard ADF operation, you can check in ADF Developer Guide.
Andrejus
Hi Andrejus,
ReplyDeleteDo you have any idea about implimenting the same in oracle forms.Can i make this as a jar and use it in Oracle forms.
Hi,
ReplyDeleteI don't think you can use it in Forms.
Regards,
Andrejus
Hi to all. I have not any chance to move my application to 11g and I'm needing to show some search results in a treeTable 10g component, but I have to show more than one root node per page. ¿Does somebody know if there is a way to do that in 10g?. I really appreciate any help: code sample, blog post or recommendations. Thanks in advance. Mauricio.
ReplyDeleteHi Andrejus,
ReplyDeleteThank you for this solution. I implemented it to my application, and it was working fine (I thought) with 11.1.1.3. Now we upgraded to 11.1.1.4 and I encountered an issue. (I am not sure if it is related to the upgrade or not. It could be me causing this problem.)
The issue is that it does not delete grand children nodes. The tree structure displays correctly in my tree table. When I select a parent node and then try to delete it and its all descendants, it just deletes the direct child and the parent node itself. When I debug, getChildren() returns null for the child node though the child node has several grand children nodes. The funny thing is that when I select the child node and try to delete it, getChildren() returns the correct number of elements.
Do you have any suggestions for me? Thank you for your help in advance!
Hi,
ReplyDeleteLatest public release is 11.1.1.3. I cant test with internal 11.1.1.4
Regards,
Andrejus
Hello Andrejus,
ReplyDeleteWhat if you do not have an entity object? I am trying to do something similar but I have a view object and view link getting the information from the database table. When I create the tree and the detail table, nothing gets populated. Any suggestions as to what I might be doing wrong?
Thanks
-H
Hi,
ReplyDeleteIt should work even without EO, it should be fine to have only VO and ViewLink.
Most probably there is problem in VO.
Regards,
Andrejus
Well the adf Tree works. But the detail table does not work. It defaults to the first value. And does not even change when I click on something on the tree. (I do have partial Trigger).
ReplyDeleteWeird thing is my AppModule works fine so I know the logic with the view links works okay.
Any idea what else it could be?
Thanks
-H
Hey Andrejus,
ReplyDeleteI'm to refine the classical master-detail app using tables into "tree as master tree/table as detail" application.
The problem is the binding for the detail,(as each part uses its own model, tree and table respectively)
so detail shows all data despite the master record clicked in the tree.
Could you comment on to help please?
Regards,
Alexander Bondarenko
oradevpro@yandex.ru
----------------------
here's one more, with my e-mail,
so please disregard the previous
post
Is there a way to show an attribute of a table that is a view accessor? Like when building LOV's except in a tree table? All I want is to show a Name instead of the id. I did it in a form using view accessors and made it an LOV that shows the Name instead of the ID. I wanna do the same thing for a tree table except read only (not LOV) and name instead of id. I wanna do this without creating a view link if at all possible (I did it for the form without using a view link) I am using ADF and Jdeveloper
ReplyDeleteYou can simply add Name field as new tree attribute - it will be rendered then. You need to have View Link, for Master-Detail relationship implementation.
ReplyDeleteAndrejus
I agree but I can have an LOV that lets me choose the names instead of IDs but cannot have a tree table that instead of an ID shows the names? That is what made me think it could be possible but you know this stuff a billion times better than me, sorry if the question was stupid
ReplyDeleteIs there a way to have a select one choice LOV in a query?
ReplyDeleteSorry, I dont understand the question...
ReplyDeleteIs there a way when making a view criteria and dropping it on the page to make somehow some of the fields select one choice LOV's?
ReplyDeleteAlso while I am asking, is there any way to make manual columns on the second detail level of a tree table?
THANKS
I am trying to implement tree table, but I have a view object and view link getting the information from the database table. When I create the tree and the detail table, nothing gets populated. Any suggestions as to what I might be doing wrong?
ReplyDeleteThanks
-Mamatha
Hi Andrejus,
ReplyDeleteI am working on ADF tree and have come across a issue. I am populating my tree with ADFBC. The tree is of two level. The root level is the rows of the view object MenuTableView and the second level values are populated from SubMenuVO. The views have parent child relationship.
I want to manipulate the rows before they are rendered as trees. By manipulation I mean I might delete some of the rows based on user permission before they are rendered as a tree. What is the best way to do this?
How does a adf tree calls the AM & VO classes? I just added this code in my AM but I dont get any sysout? Seems the AM methods are not called by the tree except the constructor.
public class MenuAMImpl extends ApplicationModuleImpl {
/**
* This is the default constructor (do not remove).
*/
public MenuAMImpl() {
System.out.println("MenuAMImpl instantiated");
}
public static void main(String arg[]){
new MenuAMImpl().getMenuTableView1();
}
/**
* Container's getter for MenuTableView1.
* @return MenuTableView1
*/
public MenuTableViewImpl getMenuTableView1() {
System.out.println("--- Inside getMenuTableView method of AM ---");
ApplicationModule am=Configuration.createRootApplicationModule("model.am.MenuAM", "MenuAM");
MenuTableViewImpl menuView=(MenuTableViewImpl)am.findViewObject("MenuTableView1");
//RowSetIterator iter=menuView.getRowSet();
while(menuView.hasNext()){
MenuTableViewRowImpl mainRow= (MenuTableViewRowImpl)menuView.next();
System.out.println("-- AM - parent row-"+mainRow.getPermissionExp());
System.out.println("-- AM - parent row-"+mainRow.getMenuDisplayName());
SubMenuVOImpl submenuView=(SubMenuVOImpl)mainRow.getSubMenuVO();
while(submenuView.hasNext()){
SubMenuVORowImpl childRow=(SubMenuVORowImpl)submenuView.next();
System.out.println("-- AM - child row-"+childRow.getPermissionExp());
System.out.println("-- AM - child row-"+childRow.getMenuDisplayName());
}
}
return menuView;
}
/**
* Container's getter for SubMenuVO1.
* @return SubMenuVO1
*/
public SubMenuVOImpl getSubMenuVO1() {
return (SubMenuVOImpl)findViewObject("SubMenuVO1");
}
/**
* Container's getter for ParentChild1.
* @return ParentChild1
*/
public ViewLinkImpl getParentChild1() {
return (ViewLinkImpl)findViewLink("ParentChild1");
}
}
The idea is to eliminate the rows at either parent or child here istelf , I mean the AM. but seems the VO's are getting called by some other method and not getter methods of AM? How the the VO's getting called in case of tree?
Hi,
ReplyDeleteProbably you would need to override VO Impl class, and work with rowset. Not AM Impl class.
Andrejus
Hello Andrejus, thanks for the post.
ReplyDeleteI would like to know if you could show us how to use the treetable together with a separate table, to represent a Master-Detail-Detail three-level relationship. In this case I am facing the same problem as Harleen, that is: "The detail table does not work. It defaults to the first value. And does not even change when I click on something on the tree. (I do have partial Trigger).
Weird thing is my AppModule works fine so I know the logic with the view links works okay."
Is there a way to fix the behaviour on the UI side by using bindings properly?
Hi,
ReplyDeleteI need to create tree from this kind of data.
col1 col2 col3 col4
---------------------------------
A1 B1 C1 D1
A1 B1 C1 D2
A1 B1 C2 D3
I want to display the tree as :
A1
---->B1
--------->C1
-------------->D1
-------------->D2
--------->C2
-------------->D3
I dont have parentid, child_id kind of relationship in the table, so cannot create a self accessor view link.
How can I do that? Please help.
Thanks,
Sachin
Hi,
ReplyDeleteSearch on Table Tree View is not working as expected.
I'm working on a Table Tree View, and am facing some strange problem.
Lets say the Tree view is as follows. FetchSIze is 1000.
Case#1 Search Box: XA -> ENTER
A
XA
XB
XC
B
C
D
E
It works fine, it starts search from A and goes fine.
Case#2: Search Box: XA -> ENTER
If Search for same thing again, it starts search from B or C, not from A.
Code for the same:
CollectionModel model = (CollectionModel) tree1.getValue();
treeBinding = (JUCtrlHierBinding) model.getWrappedData();
JUCtrlHierNodeBinding root = treeBinding.getRootNodeBinding();
Found = false;
RowKeySet resultRowKeySet =
searchTreeNode(root, searchType, searchString);
RowKeySet disclosedRowKeySet =
buildDisclosedRowKeySet(treeBinding, resultRowKeySet);
tree1.setSelectedRowKeys(resultRowKeySet);
tree1.setDisclosedRowKeys(disclosedRowKeySet);
AdfFacesContext.getCurrentInstance().addPartialTarget(tree1);
private RowKeySet searchTreeNode(JUCtrlHierNodeBinding node,
String searchType,
String searchString) {
RowKeySetImpl rowKeys = new RowKeySetImpl();
if (Found == true) {
return rowKeys;
}
Row nodeRow = node.getRow();
if (nodeRow != null) {
String compareString = "";
Object attribute = nodeRow.getAttribute("ATTRIBUTENAME");
if (attribute instanceof String) {
compareString = (String)attribute;
} else {
compareString = attribute.toString();
}
if (compareString.equals(searchString) {
rowKeys.add(node.getKeyPath());
Found = true;
}
}
If (FOUND = false) {
List children = node.getChildren();
if (children != null ) {
for(JUCtrlHierNodeBinding _node: children) {
RowKeySet rks = searchTreeNode(_node, searchType, searchString);
if (rks != null && rks.size() > 0) {
rowKeys.addAll(rks);
}
}
}
}
return rowKeys;
}
It seems like Children cursor is set to an index, may be I need to reset it
Please suggest.
In continuation to the above comment: Search on Tree Table is not worknig as expected.
ReplyDeleteThe problem is "The child nodes iterator get set to last search node or something". The below method is setting that it seems:
private RowKeySet buildDisclosedRowKeySet(JUCtrlHierBinding treeBinding,
RowKeySet keys) {
RowKeySetImpl discloseRowKeyset = new RowKeySetImpl();
Iterator iter = keys.iterator();
while(iter.hasNext()) {
List keyPath = (List)iter.next();
JUCtrlHierNodeBinding node =
treeBinding.findNodeByKeyPath(keyPath);
if (node != null && node.getParent() != null &&
!node.getParent().getKeyPath().isEmpty()) {
discloseRowKeyset.add(node.getParent().getKeyPath());
RowKeySetImpl parentKeySet = new RowKeySetImpl();
parentKeySet.add(node.getParent().getKeyPath());
RowKeySet rks = buildDisclosedRowKeySet(treeBinding, parentKeySet);
discloseRowKeyset.addAll(rks);
}
}
return discloseRowKeyset;
}
Can you please suggest how to resolve this?
In continuation to above Search on Tree Table not working as expected....
ReplyDeleteSolution:
After changing the RangeSize on ViewObject from 25 to 100, it worked.
As there are more than 25 nodes under the root, it picked up the next 25 from current selection.
Your approach is wrong - it will be performance killer.
ReplyDeleteYou should search directly inside table, construct node key and disclose it. Dont search through ADF Tree directly - this is my advice.
Andrejus
Hi Andrejus,
ReplyDeleteI am trying to improve the performance of the tree table and facing few issues in doing this...
I am using tree table to represent Question - Answer list at different levels and the view link is self referenced. We are showing only one column of the tree table with the following details...
Question Desc
Answer - this can be text, checkbox, radio - User has the option to enter the answer and save it.
User has the provision to enter comments and bugs along with the answer. For this two links are provided Add Bug and Add Comment, when user clicks on Add Comment link is hidden and one text area is shown to the user.
If there are any existing comments they will be shown below.
Comments and Bugs are separate VO's and they have view link with the QuestionAnswerVO. In the bean class, I wrote the logic to get the RowIterator of the CommentsVO and BugsVO for each question and send it as list to UI.
Here are the two performance issues that I am facing...
1. When I click on Add Comment sometimes it is taking long time to show the text area to enter the comment. When I click on Add Comment I have PPR to refresh only Add Comment link and text area component.
I observed that when I click on Add Comment link it is submitting the whole page and the complete tree table is loaded again and it is taking lot of time for this to complete.
Could you please suggest any idea to improve the performance?
Thanks,
Ravindra
In addition to my previous comment on performance issue...
ReplyDeleteBased on the answer selected for the parent question I have to refresh the child questions
Assume that the hierarchy is like this...
Q1 (if answer of the parent question is set to Yes, then I have to show only the questions which are set to Yes. In this case if the parent answer is Yes then I have to show only Q2. If it is No I have to show Q3 and Q4)
- Q2 (Yes)
- Q3 (No)
- Q4 (No)
For this I am handling the logic as below...
1.If the values are already stored in the database then doing the below logic...
In VOImpl.java
@Override
protected ViewRowSetImpl createViewLinkAccessorRS(AssociationDefImpl associationDefImpl,
ViewObjectImpl viewObjectImpl,
Row row,
Object[] object) {
ViewRowSetImpl viewRowSetImpl = super.createViewLinkAccessorRS(associationDefImpl, viewObjectImpl,
if (columnName.equalsIgnoreCase("AnswerVO")) {
//We will execute the below logic only if the user has entered an answer
if (isBooleanQts && (answer != null && answer.trim().length() > 0)) {
ViewCriteriaManager vcm = viewObjectImpl.getViewCriteriaManager();
ViewCriteria vc = vcm.getViewCriteria("EnableChildQuestions");
VariableValueManager vvm = vc.ensureVariableManager();
if ("Yes".equalsIgnoreCase(answer)) {
vvm.setVariableValue("answerBind", "Yes");
} else {
vvm.setVariableValue("answerBind", "No");
}
viewObjectImpl.applyViewCriteria(vc);
} else {
viewObjectImpl.removeApplyViewCriteriaName("AnswerChecklistEnableOnParentVOCriteria");
}
}
}
2. If the values are dynamically by the user then in the value change event I wrote the below logic...
Row currentSelectedRow = found[0];//Get the current selected row
currentSelectedRow.setAttribute("Answer", newValue);
RowSet childAnswerChecklistRowSet = (RowSet)currentSelectedRow.getAttribute("AnswerChecklistVO_2");
if (childAnswerChecklistRowSet != null) {
childAnswerChecklistRowSet.executeQuery();
}
if (rowDataObj.hasChildren()) {
DCIteratorBinding childIterBinding = rowDataObj.getChildIteratorBinding();
RowSetIterator rowSetIter = childIterBinding.getRowSetIterator();
Row[] rowsArray = rowSetIter.getFilteredRows("EnableOnParentAnswer", newValue.equals("Yes") ?"No" : "Yes");
for (Row row : rowsArray) {
row.removeFromCollection();
}
}
Could you please suggest any idea to improve the performance?
Thanks,
Ravindra
Hi,
ReplyDeleteYou can try to see if this hint will help you:
http://andrejusb.blogspot.com/2011/12/tuning-adf-tree-retain-view-link.html
Andrejus
Andrejus,
ReplyDeleteIf I set that flag I could not able to see Comments and Bugs i.e. the VO iterator's that I fetch for each row.
Thanks,
Ravindra
Hi,
ReplyDeleteI see this is complex case, I can't give advice my comment. Proper advice would require work on your code...
Andrejus
Andrejus,
ReplyDeletePlease suggest is anything that I can do for this?
1.
In each row of the tree table I have few links that show additional data. When I click on these links the size of the row is getting expanded, I mean the height of the row gets increased and this results in last row getting shrinked. I am seeing this issue only when I try to refresh particular component in a row and not the whole tree table.
Code: My tree table is having following structure...
inside center facet.
2. In the popup if I scroll the tree table till the last row and close the popup and open again it is not showing from the first row it opens the poup which will show the last few rows and user has to use the scroll bar to move up.
Thanks,
Ravindra
Hi Andrejus,
ReplyDeleteI have created two programmatic VOs with parent child relationship.There are no entity objects as my data is coming from web-service.
I am able to display master detail relationship using ADF tables but when I am using ADF tree, only parent elements are populated.
Do we need some extra work for Trees for programmatic VO?
Thanks,
Minal
Hello, i'm trying to add a child node with a button, the idea is that when i click Add in the current node, i need to add a child on the tree table, i've tried catching the current node and creating a row with the parent values, and it works but it adds to the tree table 2 rows, one at the level required and one more at the principal parent node, any suggest?
ReplyDeletehi , i have a scenario where i am using check boxes to select detail part of tree
ReplyDeleteand on a button click i have to get all checked rows
how can i do this?
Our app has a large af:tree component. It was bound to backing bean in pageflowscope. Realizing that's it's not good to bind components to anything longer than requestScope I changed the binding to use ComponentReference as specified by best practices. This broke our desired behavior for when we navigate from tree to page that edits' the node, then back to the tree. The disclosed state is not being remembered anymore. How do I restore the tree state so that all disclosed rows remain disclosed when navigating away and then back?
ReplyDeleteYour able is still based on ADF BC? May be try to use Retain View Link Accessor option for VO tuning.
ReplyDeleteAndrejus
Is it possible to get the Master table in editable mode. I have a requirement where I need to show Department(Master) -> employee(Details) in tree table but I want Department attributes to be editable. Is this possible using af:treeTable?
ReplyDeleteHi Andrejus,
ReplyDeleteI am trying to form a tree table based on read only view object where query return data as below
Employee-ID-1 FirstName1 LastName1 Document1
Employee-ID-1 FirstName1 LastName1 Document2
Employee-ID-2 FirstName2 LastName2 Document3
Employee-ID-2 FirstName2 LastName2 Document4
Employee-ID-3 FirstName3 LastName3 Document5
Employee-ID-3 FirstName3 LastName3 Document6
In tree table we would like to display as below
Employee-ID-1 FirstName1 LastName1
Document1
Document2
Employee-ID-2 FirstName2 LastName2
Document3
Document4
Employee-ID-3 FirstName3 LastName3
Document5
Document6
Question: Can we achieve this tree table from Read Only View Object?
Thanks in advance.
Tree table using ADF Read Only View Objects
ReplyDeleteThanks for the article.
ReplyDeleteThe sample code is not available: http://jdevsamples.googlecode.com/files/TreeComponents.zip yields an error 404
Is there a place where I can get this code?
Thanks in advance
I have changed download URL, try now - should be working.
ReplyDeleteAndrejus
Hello, the new versions of jdeveloper (12.1.3), variable #{node} doesn't show the attributes of table child. How I can show the values of table child into the af:columns like your example with new versions of jdeveloper?
ReplyDeleteThanks an regards.