Login Register

Tree

tree.png

The trees we see in User Interfaces help sort out long, heirarchical lists. A file system is the classic example, with Windows using it in Explorer and Macintoshes with its folder windows. The Dijit tree widget is like that. The Tree widget itself is simple, but the real power comes in the data you pass - this represents the heirarchical structure of the tree. This data is fed by the powerful dojo.data API.

Dojo makes easy trees easy, and hard trees possible. In particular, you can:

  • Build rooted or rootless trees (forests)
  • Nest trees to an arbitrary depth ... each branch is independently expandible
  • Apply different icons to different leaf or branch classes
  • Connect your tree to any dojo.data store implementing the Identity API.
  • Attach code to events. Events fire when users expand, contract or click particular nodes.
  • Programmatically build trees. Add, remove or disable nodes programatically.
  • Manipulate the Dojo.data store directly, which manipulates the tree indirectly
  • Allow nodes to be dragged and dropped through the familiar Dojo DnD API.

Topics?

Could someone summarize the topics that Tree and TreeNode publish?

from code doc:

dojo.declare(
"dijit.Tree",
dijit._TreeBase,
{
// summary
// Tree view does all the drawing, visual node management etc.
// Throws events about clicks on it, so someone may catch them and process
// Events:
// afterTreeCreate,
// beforeTreeDestroy,
// execute : for clicking the label, or hitting the enter key when focused on the label,
// toggleOpen : for clicking the expando key (toggles hide/collapse),
// previous : go to previous visible node,
// next : go to next visible node,
// zoomIn : go to child nodes,
// zoomOut : go to parent node

It seems the tree publishes the events, and so it seems TreeNode doesn't publish any.

A couple of question about the sample code

The article leaves some questions unanswered.

First, why do I have to define twice what attribute is being used as a label? First, in the data object itself (by using the label attribute) and then again as an attribute of the Tree (using the labelAttr attribute). That doesn't seem very intuitive to me.

Second, what's the deal with the 'type' attribute of the data objects? It's not explained how it affects tree behavior or rendering (if it does at all).

Only label and id matter

Everything else is extra. I use the 'type' attribute to differentiate between different TreeNode types, like folders versus subfolders versus leaf items (different icons). I also have lots of other data stored as extra attributes that is not used in the Tree rendering at all, but is shared with other widgets in the application.

Anni

adding/removing tree nodes?

Hi,

we need to dynamically and and remove nodes from the tree. Until now I wasn't able to figure out how to do this. I wrote this code which I thought would add a new node at the top level:

dojo.addOnLoad(function() {
            dijit.byId("myTree").addChildren([{item:{nodeName:'N1',type:'rootItem'}}]);
        });

But this doesn't actually do anything. At least no visible node is added to the tree. Am I missing something?

Use the data store

This part in the Tree is very confusing. It took some time for me to realize, that I need to add nodes to the tree via its store object. If you look the addChildren() code, you probably notize that the function takes an array of items that already exist in the data store.
So, it goes like this:
You add stuff to you ItemFileWriteStore with newItem(), where you can also declare the parent. The store method then publishes onNew event, that the tree controller catches. Controller then calls addChildren. So, adding items to your data store automatically creates them as tree nodes in the tree.

At least this is how it works in 0.9.0 stable, don't know, if this has changed in the nightlies again....

Anni9

RE: adding/removing tree node?

Hello,

If anyone is wanting to do this and is struggling then this is how I eventually got it to work. First of all I used an ItemFileWriteStore as I'm passing (well planning to) a JSON object. I declare this as global and initialise it with the identifier and label along with blank array for items (Sorry about the names it's still in test mode): -

var topStructure = {identifier: 'name', label: 'name', items: []};
var someThing = new dojo.data.ItemFileWriteStore({data: topStructure});

Next I add simple node that will be my parent: -

var topNode = {name:'anotherParent' ,type:'Directory' ,directoryPath: 'C:\\data\\anotherParent'};
someThing.newItem(topNode);

Side note: In my HTML I have a tree defined like (Ignore the event)

div dojoType="dijit.Tree" store="someThing" query="{type:'Directory'}">
script type="dojo/method" event="onClick" args="item">
document.getElementById("fileSelected").value = item.directoryPath;
/script>
/div>

Now I have another function that is assigned to an event elsewhere in the page that looks like this:-

function checkIsItem(){
someThing.fetchItemByIdentity({identity:'anotherParent',
onItem:function(item){
someThing.newItem({name:'lroseve2',type:'childDirectory',directoryPath:'C:\\data\\maildata\\lroseve2'},
{parent:item, attribute:'children'});
}});
}

This function will add a child to the top level parent. It does this by first locating the parent using the fetchItemByIdentity on the store and using the onItem method/function to call the newItem to append the new child, passing through the parent item.

Hope this helps someone.

Chris

updating json reply received from url

Hi,

I used someThing.newItem to update a tree, it works correctly if the items are passed explicity. I am unable to get it working if the items are as json object received from server. For learning I am trying the following,

1. From webserver on load I request for list of directories.
2. I want to display this as tree and then be able to use drag and drop to do ftpdownload.

my code is as follows,

templfilestore = {identifier:'name',label:'name',items:[]};
     var lfilestore = new dojo.data.ItemFileWriteStore({data: templfilestore})
     
     temprfilestore = {};
     var rfilestore = new dojo.data.ItemFileWriteStore({data: temprfilestore})
     
     templfiles = ''
     
     function init(){
     alert("into Load");
     GetLfiles();
     //GetRfiles()
       
     };
     
     //get local files(web-server files)
        function GetLfiles(){
        alert("into Getlfiles"); 
        var templfiles = new dojo.data.ItemFileReadStore({url: "http://localhost:8080/pylocalfiles?"});
        var request = templfiles.fetch({query: {type:"folder"}, onComplete: createltree});
         alert('outgoing')
         alert(templfiles);
       var createltree = function(items,request){
          alert('into createltree');
          alert(items.length)        
            for (var i=0; i

Can anyone help. Thanks in advance.

Gp

Yes, thanks, I realized this

Yes, thanks, I realized this meanwhile. I don't like this store API thing a lot, it adds unnecessary complexity where I expect a client-side script library to be simple and lightweight.

I tried using the ItemFileWriteStore, which implements newItem(), but failed to achieve the desired result. I wrote a comment on the ItemFileWriteStore page about a very strange code snippet in the ItemFileWriteStore implementation which I think is causing the issue.

Actually, we're going to stick with Dojo 0.4 for now. For now, I don't like what I see happening with Trees, Data Stores and so on. Feels unfinished and strange to handle. Also way too complex to remain intuitive and comfortable to use.

(I'm sorry, this actually belongs under Annie's last post as a reply)

Expanding nodes programmatically

Sorry about this pretty basic-seeming question, but I can't seem to figure out how to expand tree nodes programmatically. I'm working on a "help viewer" that has the documentation structure as a Tree in the left pane and the page displayed in the right pane. Now, if I hyperlink from one page to another, I want to expand and focus on the Tree node that matches that page. What do I do?

Another thing that I think should go on this page is a walkthrough on how to use the extension points. For example, exactly what should you do to set the icon of a tree node based on the item properties in the data store? (I did eventually figure this out, but it would have been a lot faster to look up here or even if there was a sample on a test page.

(To matt -- I like the new separation between the data store and the UI; however, it does take some time to figure out, which means that the documentation could use some work.)

/Petteri

Expanding tree nodes programmatically

A tree extension to expand a node programmatically, when you know the corresponding store item:

function expandNode(item) {
  var identity = this.store.getIdentity(item);
  var node = this._itemNodeMap[identity];
  this._expandNode(node);
}

Expanding nodes

I'm also having trouble with nodes. I can not get a node to expand at all. I'm using the examples above substituting _reference in the data store (as discussed above). The + icon is displayed but will not expand. The + icon just changes to a blue dot. I don't know if this is a documentation problem or a bug in the code or just my lack of experience with Dojo. I'm using the 0.9 download. Although this example is useful, it would be better to have a complete working example that leaves nothing to interpretation - like most of the other widget examples. I'm brand new (first day) to Dojo - what did I miss?

I had the same issue too

I had the same issue too using 0.9 and noticed the blue dot appearing in IE6.0.29 but not in Firefox. Hope that helps someone.

getting rid of the root node

I want to create a Tree and have the root nodes be the top level items in the json data returned by the store. But it seems the Tree always has a single root node and the json data items are always children of this root node. How can I get rid of the default root node?

Clicking rightButton to add or delete TreeNode.

recently, a friend on the internet asked me how to implement clicking right button to add or delete the dijit.Tree 's item. i didn't find out the good way to implement it after thing about it for a while . Finally, I extended the dijit.Tree for adding an "onmousedown" event . In this way , it became easy.

this example file contains the following useful skills: "custom component "," dijit.Tree "," dojo.data " , "dijit.Menu "....

the Demo is : http://www.dojocn.cn/dojo/dojocn/test/impl_DTree.htm
.

Tree with checkbox

Good day.

I was looking at creating a Tree widget with a checkbox in it. The checkbox will have 3 states: (1) partially checked, (2) checked, and (3) unchecked. It would work the way a feature-selection widget does in an installer.

It's something like this:

  • a
    • c
    • d
    • e
  • b
    • f
    • g
    • h

Checking "a" would check "c", "d", and "e". Unchecking "d" would turn "a" into a partial check. Unchecking "c" and "e" would turn "a" back into unchecked.

Hope this is clear enough and am hoping that someone would be able to help

Thanks!

Arnel

Checkboxes on Tree...

I did something very much like that.

First off, this information may already be obsolete -- Tree has evolved a lot for 1.0.0, and may actually be able to do this just by manipulating the data in the data store, without having to loop through the tree.

(1) Write a getIconClass method that returns a className for "checked" and "unchecked" depending on the treeNode.item properties (where treeNode is the treeNode under consideration and item is the matching data store item). Something like this:

getIconClass : function( item )
{
        if( item.activity == "INACTIVE" ) return "uncheckedIcon";
        else return "checkedIcon";
}

(2) Add an onClick handler for the treeNode. The onClick handler should toggle the "checked" property of the item matching the clicked treeNode, then fetch() its descendants from the dataStore, and set their "checked" property to match the one you clicked. (No sample provided since I don't have an exact analogy to hand, but I'm sure you can figure it out.)

(3) Write a script that loops through the tree (or just the branch you wrote) and re-checks each node's iconClass using the getIconClass method from step (1). Something like this:

// this.TREE_ID is the ID of the tree you're playing with
refreshTreeDisplay : function()
{
        var widg = dijit.byId( this.TREE_ID );
        var chld = widg.getChildren();
        for( var i = 0; i < chld.length; i++ )
        {
                this._refreshNodeIcon( chld[ i ] );
        }
},
// this.ICON_CLASSES is an array of all classNames you apply to
// the tree's iconNode, in this case [ "checkedIcon", "uncheckedIcon" ].
_refreshNodeIcon : function( treeNode )
{
        for( var i = 0; i < this.ICON_CLASSES.length; i++ )
        {
                dojo.removeClass( treeNode.iconNode, this.ICON_CLASSES[ i ] );
        }
        dojo.addClass( treeNode.iconNode, this.getIconClass( treeNode.item ) );
}

RE: Checkboxes on Tree...

Thank you for your very quick response. I highly appreciate it. But do you think you can supply a live URL or maybe an actual working code. I know it's asking too much but it would be greatly appreciated if this can be supplied. I can be reached at saklay [at] gmail dot com.

Thanks in advance.

Getting Tree Nodes

What is the best way to retrieve a Tree._Node object, to expand it or apply the focus, for example? Seems like I should be able to send the identifier to some method, and get back the object. And it doesn't seem like I'd want to do something tree-specific via the corresponding data store...

Please use the support Forums

Support Questions belong in the Support forums, not the book pages.

-Karl

Support forums are hard to find for newbies like me....

It's somewhat difficult for new users to find the correct support forum to ask questions like these (which is why you see so many support questions in the Book of Dojo).

Perhaps we should consider adding links to each page to the correct support/developer forum? Two simple links in the page: "Link to support forum for this topic" and "Link to developer forum for this topic"? That will likely cut down on the number of support questions in the wrong place.

Tree with checkbox

How to add checkbox with tree..

I am hoping that someone would be able to help

Thanks!
Santosh

Using innerHTML from server XSLT response as AJAX tree output

Hi. I am working on a J2EE project, and our current framework uses XSLT technology to render the HTML response from the J2EE server. Our application uses dojo v0.4 for AJAX requests to the server and we use '.innerHTML' property to set the server response to the HTML from the dojo.io.bind response.

Now, we have a new UI design where dojo/dijit Tree is planned to be used, with AJAX - but the problem is that it can only output JSON response (at least as I've tried in dojo v 0.4).

1. Can you kindly give an example that can dynamically add a node to a tree - by setting the innerHTML attribute? (since this is the one supported by our framework XSLT). I know I can use XSL to create JSON (but will deviate from our project's standard way of showing output), but AJAX is pretty popular for innerHTML use, so with dijit Tree is it possible?
It is OK if the example uses dojo v1.0.2 since we are planning to upgrade anyway.

2. Instead of the TreeRPCURL as in v 0.4, can I use the new equivalent of dojo.io.bind, dojo.xhrGet or dojo.xhrPost to fetch the data from the server and add the node to the tree?

Your help is very much appreciated.

By the way, thank you for Dojo. Great work =)

You can't

(1) In Dojo 1, the Tree is linked to a dojo.data store; to add nodes to the tree, add items to the data store. So you can't do it directly on the tree via innerHTML (not without making a total mess of it anyway). Read up on the dojo.data API and the provided stores for more on this. (It's pretty simple, really, and once you get the hang of it, much nicer than the API in 0.4.)

(2) You can most certainly use dojo.xhrGet or .xhrPost to talk to the server. Using JSON in the messaging is easiest, but it's almost as easy to use XML -- you just have to write a utility method to translate XML to JSON client-side.

(3) I would recommend that you post this on the support forums [ http://www.dojotoolkit.org/forums/forums/support/dijit ]; I've been told off by the admins once for posting questions like this here. :-)

Thanks for the valuable info

Thanks for the valuable info. Sorry for the mistaken posting.

two icons

Is there a way to add two icons two a tree node?
The existing getIconClass doesn't easily support two icons.
You can return a icon classes with two different classes but it still treats them as one item.