Monday, January 7, 2013

Working with the tree in Apex

The tree in Apex is based on the jsTree plugin and is version 0.9.9a2 for apex version 4.0, 4.1 and 4.2.
There are quite often questions about how to work with the tree and perform some basic actions on it. Perhaps some folks just don't know that there actually is documentation available and where it resides. You can find the documentation in your apex_images folder under libraries\jquery-jstree\0.9.9a2.
Of course, if you're no javascript or jQuery wiz, you might find the documentation quite confusing. Even if you are, it isn't all that clear at first and i too struggled a bit initially with no examples available.
Before looking at the below questions i want to start off with this: all of the functions that are described in the documentation require a tree instance to invoke them. The methods are not static ones. Getting a tree instance:
Note that you could have more than one tree on a page and therefor i would advice to provide a static id to the tree region(s).

How to get a tree reference

Documentation: This functions returns a specific tree instance by an ID or contained node.
This means that we need an actual element that resides in the tree. Since the markup generated for the tree is always the same, and the top level element is a div with class tree, this element can easily be fetched.
var l$Tree = $("#myStaticRegionId div.tree");
With this element the tree reference can be retrieved
$.tree.reference(l$Tree)
This reference will be required for all actions performed on this tree.

Common questions

  • I want to search the tree

    $.tree.reference(l$Tree).search("text_youre_looking_for");
    Oh, but what does this do? It doesn't return anything? That is correct.
    From the documentation: The function triggers the onsearch callback, with the nodes found as a parameter.
    And under callback.onsearch: Default is:
    function(NODES, TREE_OBJ) { NODES.addClass("search"); }

    So, nodes which contain the text searched for will have a class "search" appended to them.
    To retrieve those nodes, use
    $(".search")
    Now, if you're using a tool such as Firebug, you might notice that a POST is being made to the server. It will fail however, each and every time. This is because for some reason the defined defaults have not actually been set in the tree initialisation. You can fix this by performing this:
    $.tree.reference(l$Tree).settings.data.async = false;
  • I want to get a node's text

    $.tree.reference(l$Tree).get_text()
  • I want search to do something different than assign a "search" class

    By default the "search" class will be set on the anchor tag of the list element. You could alter the behaviour by overriding the default onsearch function.
    $.tree.reference(l$Tree).settings.callback.onsearch = function(NODES, TREE_OBJ){
      $.each(NODES, function(){
        console.log("Matched node: " + this);
        $(this).addClass("search2")
      });
    };
    
    I'd show how to rename a node, but by default the rename won't work as it has been disabled (for some reason). You could do this by altering the .text() of the retrieved element, but that will clear out the ins-element. So if you go that route, append an ins element and then some text.
  • I want to do something when a node is selected

    $.tree.reference(l$Tree).settings.callback.onselect = function(NODE, TREE_OBJ){
    console.log("Selected node: " + NODE);
    };
    
    Don't use a .click event handler on the list items as clicks are fired for the element and its parent elements. If you want to use a click handler for each indivual element, you can use a selector like this, which would select the first anchor tag in each list element:
    $("#static_id div.tree li>a")
  • I want to get the currently selected node

    $.tree.reference(l$Tree).selected
  • I want to set a node as being selected (without clicking the node)

    $.tree.reference(l$Tree).select_branch(node, false);
    Where "node" would be either a tree node reference, dom element or jQuery object. The second argument is whether to multiselect or not.

    Small example on a tree based on EMP:
    $.tree.reference(l$Tree).search("KING");
    $.tree.reference(l$Tree).select_branch($(".search"), false);
    
  • I want to do something when a node is double-clicked

    $.tree.reference(l$Tree).settings.callback.ondblclk= function(NODE, TREE_OBJ) { 
    console.log("Double clicked node: " + NODE);
    };
    
  • I want to open or close a node/branch

    var lReturn = $.tree.reference(l$Tree).open_branch(node);
    var lReturn = $.tree.reference(l$Tree).close_branch(node);
    
    Where "node" would be either a tree node reference, dom element or jQuery object.
  • I want to do something when a node is opened or closed

    $.tree.reference(l$Tree).settings.callback.onopen= function(NODE, TREE_OBJ) { 
    console.log("Opened node: " + NODE);
    };
    
    $.tree.reference(l$Tree).settings.callback.onclose= function(NODE, TREE_OBJ) { 
    console.log("Closed node: " + NODE);
    };
    
These examples should provide you with enough knowledge about how to use the possible functions and callbacks of the tree.
You can also take a look at this small example i set up on apex.oracle.com!

8 comments:

  1. Hi Tom very nice blog ...
    good knowledge for APEX developer

    Cheers

    ReplyDelete
  2. I have tried so many times this demo's Credentials not WORKING please do something

    ReplyDelete
  3. demo Credentials are not working can someone help with it

    ReplyDelete
    Replies
    1. Sorry. Someone keeps getting the account locked, it's really annoying. I need to find some time to change the authentication around. For now I've unlocked the account again.

      Delete
  4. Hi Tom, have you explored the new tree widget coming in APEX 5? It would be very helpful to know how to accomplish all of what you explained in this post, but with the new tree. Thanks!

    ReplyDelete
    Replies
    1. Hello Harvey! Many of the basic options are still doable indeed in apex 5. The entire framework changed of course, because the apex team has created their own widget, as you stated. I'll see when I can scrape together my code and - most importantly! - time. Some of these things are on the OTN forums already too, such as getting the selection.

      Delete
  5. Hi Tom, what if selected node repeats in another parent, then it gets first in the list. how to get the selected node based on parent node?

    ReplyDelete