Adding a treeview to a page
Let's start with the basics. The treeview is a built-in region component called "Tree". Simply drag it from the Regions palette to the content body of the page.If you intend to manipulate the treeview using Javascript, you should assign the region a static ID (such as my-treeview).
You need to specify a query as the source for the treeview.
The treeview query
This sample query is taken from the help text, and shows you what the treeview query needs to look like in terms of columns. It uses the sample EMP table (usually installed in the sample SCOTT schema in the database, see for example this blog post if you need to recreate it).Since a tree is used to display a hierarchy, we use the connect by clause in the query to link the item (employee) with the parent item (manager). connect_by_isleaf and level are built-in Oracle functions/pseudocolumns that can be used with queries that use the connect by clause.
select case when connect_by_isleaf = 1 then 0 when level = 1 then 1 else -1 end as status,
level,
ename as title,
'icon-tree-folder' as icon,
empno as value,
ename as tooltip,
null as link
from emp
start with mgr is null
connect by prior empno = mgr
order siblings by ename
For reference, here is a slightly more complex query taken from the "Sample Trees" packaged application.
select case when connect_by_isleaf = 1 then 0 when level = 1 then 1 else -1 end as status,
level,
label || ': ' || name as title,
case
when item_type = 'P' then 'fa-file-text-o'
when item_type = 'S' then 'fa-caret-square-o-right'
when item_type = 'T' then 'fa-minus-square-o'
else null
end as icon,
id as value,
case
when tooltip is not null then name || ' - ' || tooltip || '% complete'
else name
end as tooltip,
case when item_type = 'P' then
apex_util.prepare_url('f?p='||:app_id||':7:'||:app_session||':T:::P3_SELECTED_NODE,P7_PROJ_ID:'||id||','||id)
when item_type = 'T' then
apex_util.prepare_url('f?p='||:app_id||':9:'||:app_session||':T:::P3_SELECTED_NODE,P9_PROJ_ID,P9_TASK_ID:'||id||','||link)
when item_type = 'S' then
apex_util.prepare_url('f?p='||:app_id||':10:'||:app_session||':T:::P3_SELECTED_NODE,P10_PROJ_ID,P10_ROWID:'||id||','||link)
end as link
from ...
Custom icons
The fourth column of the treeview query is the icon, specified as a Font Awesome class name (or whatever other icon library you have included in your application). This can either be a static value hardcoded into the query, or you can use a case statement (or a PL/SQL function) to provide different icons depending on your data. The default is no icon.Tooltips
The sixth column of the treeview query is the tooltip, ie the text that will be displayed when the user hovers over the node with the mouse. To enable tooltips, you also need to set the "Tooltip" attribute of the treeview region from "None" to "Database Column".Collapsing and expanding all nodes
Create a button, add a dynamic action to it, and set the true action to "Expand Tree", then set the affected element to your treeview region. Create a similar button for the "Collapse Tree" dynamic action.The link column
The seventh column of the treeview query is the link, ie what should happen when the user clicks on a node in the treeview. If you leave the link column set to null, nothing will happen when the user clicks a node, and you have to use Javascript to retrieve the underlying value of the selected node and do something with it (see below).If you do construct a link in the query, it can be either an external URL (outside Apex), an Apex URL (in which case you should use either apex_util.prepare_url or apex_page.get_url to construct a valid link, I prefer the latter API since it is the newer of the two), or a Javascript URL (see example below).
See second query above for an example of Apex page links created via the query.
Example of Javascript link: If you don't want to navigate away from the page when the user clicks a node, you can use a Javascript link to call some Javascript function local to the page.
Modify the query above to
select ...,
'javascript:DoSomethingWithSelectedNode(' || id || ');' as link,
...
Then add the following function to the "Function and Global Variable Declaration" attribute of your page:
function DoSomethingWithSelectedNode(nodevalue) {
$s('P1_SELECTED_ID', nodevalue);
}
Create a hidden page item called P1_SELECTED_ID and set the "Value Protected" attribute to "No" to allow us to manipulate it via Javascript.
You can now add a dynamic action that triggers "on change" of the hidden page item. The hidden item will change when the user clicks a node in the treeview, and this will in turn trigger the dynamic action.
Activate links with single or double click
This is an attribute of the tree region. The default is "Single Click", but you might want to change this to "Double Click" to support more advanced interaction (with a single click being captured by a Javascript event handler and a double click used to navigate to a different page).Getting the value of the selected node via Javascript
As described in this forum post, there are other ways of getting the selected node value (in addition to the Javascript link described above).I will quote from the relevant parts of the answer:
"With the Apex 5 tree, you can use two functions to retrieve the current selection. First of all though, you'll want to assign a static region id so you can select the tree correctly. For example, I assigned mine the id "my-treeview".
The difference between the two methods is in what they return. One returns the actual elements in the DOM, the other will get you the datamodel nodes. The datamodel will allow much easier access to the data than the dom nodes would. It depends on what you want to do, obviously."
Code snippets:
// returns the actual elements in the DOM
apex.jQuery("#my-treeview div[role='tree']").treeView("getSelection")
// returns an array of nodes
apex.jQuery("#my-treeview div[role='tree']").treeView("getSelectedNodes")
// returns just the id of the first currently selected node
// multiselection is not something enabled by default, so it is safe to just get the first id
apex.jQuery("#my-treeview div[role='tree']").treeView("getSelectedNodes")[0].id
The screenshot below shows these function calls in action:
It is also possible to set up an event handler to trigger whenever a node is selected ("Thus you can avoid having to generate javascript calls in your SQL"), like this:
// setup event handler to handle selection of nodes
apex.jQuery("#my-treeview div[role='tree']").treeView("option", "selectionChange", function(e){
console.log("Selection changed, value of selected node is " + apex.jQuery(this).treeView("getSelectedNodes")[0].id);
});
Screenshot below shows this in action:
Remembering the value of the selected node between page views
The "Selected Node Page Item" attribute is used to remember the value of the selected node between page views, so that the tree is always expanded and focused on the previously selected item when the user returns to the page that contains the treeview.
Here is what the help text says: "This item is used to save tree state, by holding the value of the last selected node. The value of the selected node can be saved to the selected item via the node link attribute, or via a page process. When the tree is reloaded, the tree is opened to the selected node value."
In other words, you put in the name of a page item in this attribute, and you need to make sure that the item contains the value of the selected node (this doesn't happen automatically).
One way to do this is as demonstrated in the second treeview query above, which sets the page item on the treeview page (P3_SELECTED_NODE in that example) in the link that navigates away to another page.
Alternatively, if you need to stay on the same page, you can use any of the Javascript methods described above to get the value of the selected node, and then use the $s() function to set the value of the page item. This item value is stored automatically in session state if you submit the page.
Finally, if you need the selected node value to be stored in session state immediately, you can use Ajax. Here's an example of code to put on the "On page load" attribute of the page:
apex.jQuery("#my-treeview div[role='tree']").treeView("option", "selectionChange", function(e){
console.log("Selection changed, value of selected node is " + apex.jQuery(this).treeView("getSelectedNodes")[0].id);
$s("P4_SELECTED_ID", apex.jQuery(this).treeView("getSelectedNodes")[0].id);
});
Then create a dynamic action that triggers on change of P4_SELECTED_ID, and the true action to "Execute PL/SQL Code". Set the PL/SQL code to "null;" (do nothing, basically) and put P4_SELECTED_ID in the "Page Items to Submit" attribute.
What this does is set the (server-side) session value of P4_SELECTED_ID via an Ajax call as soon as the value is changed (see screenshot below).
Remember to set P4_SELECTED_ID as the "Selected Node Page Item" attribute of the treeview region. You can now click anywhere in the treeview, then navigate away to another page (via any means), and when you return to the treeview, the previously selected item should be expanded and selected.
References
- Sample Trees packaged application
- Get Selected Value - https://community.oracle.com/message/13595561#13595561
- Remember selected value - https://community.oracle.com/thread/3883290
16 comments:
Great article, Morten! I am curious: have you ever tried to add search to the tree view?
@Steven: What kind of search? Client-side filtering of the visible nodes, or server-side search (trivial by referencing a page item in the treeview query) ?
- Morten
Hi,
you have to set the icon type under the attributes section of the tree.
Put in 'fa' if you want use font awesome icons.
Bye
Christian
@Christian: Great, thanks for the tip! I've updated the post with this information.
- Morten
If somebody needs dynamic tree search plugin you can find it here:
http://apexbyg.blogspot.com/2015/07/dynamic-tree-search-plug-in.html
@Marko: That's awesome! Very useful plugin. And I'm sure it' exactly what Steven F. was looking for :-)
- Morten
Great information here. As for documentation. Unfortunately for now you have to read the code in the widget.treeView source file. There are *lots* of comments in there. As for examples of where some of the more advanced features are used take a look at how page designer uses the treeView.
Hi,
I don't see "Selected Node Page Item" attribute in the treeview region in Apex5.
How can i set the selected nodes in the tree during page load?
Hi ,
This is a great blog (indeed its a pathfinder ).
+ 1 for redirecting 'read the code in the widget.treeView'
Two things are still a mystery
1] How can i set the selected nodes in the tree during page load?
2] Can we auto-select all child elements if a parent is clicked.
Hi, agree with other comments, this is a good documentation of the treeView.
In addition to the previous comment, and because I am working in multiple select mode :
$("#lovTree").treeView("option","multiple", "true");
(lovTree is the static id of the tree Region)
I am looking for the 1) how I can select nodes at page load time
and the 2) also, auto-select childs (if you know the first one, the second is a piece of cake because if children exists then it is an attribute of the node. By example, in multiple select mode, you get the array of selected nodes with :
$($("#lovTree").treeView("getSelectedNodes")).each(
function(index,node){
selection+= (selection==''?'':':') + node.id ;
}
);
and then you can use "node.children", if it is set, it is the array of children.
and then I am looking for a 3) change the click handler to toggle item selection, and do not call clearSelection().
Hi, I have done some progress on the "1)how I can select nodes in the tree during page load". Have a look here.
Hi,
How can I Expand Tree (expand all nodes) using javascript (and not using Expand Tree Dynamic action)?
Any way to expand some particular nodes (i have enabled tree multi-selection) on load?
Hi,
i'm currently working with new Apex Tree in APEX 5 and i'm missing something.
In APEX 4 i qas using this plugin for HTML Markup (http://apex-plugin.com/oracle-apex-plugins/dynamic-action-plugin/html-markup-for-apex-tree_174.html) so i can use HTML Code in my tree.
That plugin is not available for APEX 5, but on some sites i found that you can use HTML code in APEX Tree wihout any plugin, but it's not working for me.
For example I want that my ENAME column is shown in green color:
select case when connect_by_isleaf = 1 then 0 when level = 1 then 1 else -1 end as status,
level,
'< $pan style="font-weight: bold;color:green;">'||ename||'' as title,
'icon-tree-folder' as icon,
empno as value,
ename as tooltip,
null as link
from emp
start with mgr is null
connect by prior empno = mgr
order siblings by ename
In APEX 4 with plugin, my tree returned data in green color, but in APEX 5 i get this in my tree ( HTML Code is just showed, not executed):
<$pan style="font-weight: bold;color:green;">BLAKE
<$pan style="font-weight: bold;color:green;">JONES
<$pan style="font-weight: bold;color:green;">KING
I also tried with standard bold tags but also only get < b>BLAKE< /b> as returned tree title.
I tried with Tree Atributes Escape special characters turned on and turned off, but nothing.
Is there any other way so i can use HTML code in tree?
I need this so i can change text color or bold text for different conditions.
Thanks
P.S.: I replaces s with $ in span because comment doesn't allow that tag
Hi,
Your article was a tremendous help. Thanks! Do you know of a way to add a context menu to a tree view so that you can execute a change in the data such as "Move Up" to re-position a node? Any help would be appreciated.
Dude! Best APEX tree doc on the web! Thanks for this, helped me with soo many advanced workings of the tree. Perhaps change the blog name to something more appropriate ;-) so Google can find it easier?
Post a Comment