AjaxTree.com uses the DOJO ajax API to explain how to make ajax trees that are dynamic.
This section will explain in detail all of the tags that you can use to create your dojo tree implementation.
As when using any dojo functionality you must include the dojo.js file reference
<script type="text/javascript" src="javascript/dojo.js"></script>
In order to use the dojo tree widget you must also include the following required tags:
Listing 1. Required Dojo Tree Tags<script type="text/javascript">
dojo.require("dojo.lang.*");
dojo.require("dojo.widget.Tree");
dojo.require("dojo.widget.TreeRPCController");
dojo.require("dojo.widget.TreeSelector");
dojo.require("dojo.widget.TreeNode");
dojo.require("dojo.widget.TreeContextMenu");
</script>
The html tag to begin your tree definition and define the selector looks like this:
<div dojoType="TreeSelector" widgetId="AnyNameYouWant">
It is the parent div tag that surrounds the dojo tree specifications.
| Property | Description |
| dojoType | This is the html element that specifies that the Dojo element is going to be a Tree. Therefore, it's value should be "TreeSelector". |
| widgetId | This is the name of the Tree Selector. You can use anything you'd like. It is an identifier so you can refer to this specific Tree Selector if you have more than one on your page. |
The html tag to begin your tree definition and define the tree looks like this:
<div dojoType="Tree" widgetId="AnyNameYouWantForTheTree" selector="SameNameYouUsedForYourSelectorID" toggler="plain">
It is the parent div tag that surrounds all of the children nodes but is within the Tree Selector parent tags.
| Property | Description |
| dojoType | This is the html element that specifies that the Dojo element is going to be a Tree. Therefore, it's value should be "TreeSelector". |
| widgetId | This is the name of the Tree. You can use anything you'd like, just make sure it's unique to your html page. It is an identifier so you can refer to this specific Tree if you have more than one on your page. |
| selector | This is the name of the Tree Selector to use for this tree. It should be the exact same name as the one used for the widgetId for your TreeSelector div tag. |
| toggler | This tag refers to the toggle dojo functions you can use defined in dojo.lfx.toggle. These functions include: plain, fade, wipe, and explode as of Dojo 0.3.1. They are basically the animation effects used when expanding and collapsing tree nodes. |
| controller | Widget ID of an TreeController that adds additional functionality to this tree through event handlers. During initialization, the widget's "subscribeTree" method will be called with this tree as its argument. |
| selector | Optional widget ID of an TreeSelector. If none is specified, initialization will build one and assign it to the "selector" property of this tree. The default selector only supplies a "selectedNode" property for use by the tree's controller. I think this object's purpose is to allow one selected node for an entire set of trees. |
| tree | Object. This tree. Also used by "TreeNode". |
| isExpanded | Boolean. "true". The tree root node is considered to be always expanded. |
| isTree | Boolean. Always "true". |
| showGrid | Boolean, default:"true". Controls display of grid lines connecting tree nodes. Settable only on creation. |
| showRootGrid | Boolean, default: "true". Controls display of grid lines to top-level tree nodes. Settable only on creation. |
| menu | Used to specify the TreeContextMenu that is to be used by this tree |
| DNDMode | Drag and Drop Mode ex. DNDMode="between" -- this allows the user to drop a tree node between other tree nodes. |
| actionsDisabled | Used to specify which actions should be disabled for the tree. If you don't the user to be able to perform some action specify that action's name here ex. actionsDisabled="addChild" |
| DNDAcceptTypes | Drag and Drop Accept Types ex. DNDAcceptTypes="secondTree" |
The last thing you need to make any tree complete are the children nodes or tree nodes. The tree nodes
inherit their properties from the dojo.widget.HtmlWidget.
<div dojoType="TreeNode" widgetId="AnyNameYouWantForThisNode"
title="Some Title that's displayed to the user" isFolder="false">
| Property | Description |
| dojoType | This is the html element that specifies that the Dojo element is going to be a TreeNode. Therefore, it's value should be "TreeNode". |
| widgetId | This is the name of the Tree Node. You can use anything you'd like, just make sure it's unique to your html page. It is an identifier so you can refer to this specific Tree Node if you have more than one on your page. |
| title | This is the title or main lable of the Tree Node as will be viewable by the user. Some users find it helpful to use an outline type of naming convension. 1 for parent 1.1; 1.2; etc. for children of 1, etc. The title can also include html |
| isFolder | Optional Tag. Default value is false. When this value is true it forces an expand/collapse image on every node, even if it doesn't have any children. By setting it to false the expand/collapse image will only show up on a node if it has children. If it does not have a custom childIconSrc, it will display with a "folder" icon. |
| childIconSrc | If specified, a string URL pointing to the icon for the node. |
| afterLabel | String containing HTML to be rendered following the node title. |
| objectId | String identifying the represented object, for access from JavaScript. |
| tree | Object. The containing tree. |
| isTree | False. |
| isTreeNode | True. |
| isExpanded | Indicates whether the node is expanded. Always false if there are no children. |
| childIconFolderSrc | Default URL, used for nodes that are folders if no childIconSrc is specified. |
| childIconDocumentSrc | Default URL, used for nodes that are not folders if no childIconSrc is specified. |
| object | Available to store application data, an object representing the represented object. |
It is also possible to use JavaScript to dynamically create a Dojo Tree. You can do this by creating a script
such as the following:
The above code would be the same as doing this:
<div dojoType="Tree" widgetId="treeWidget" selector="treeSelector" toggler="wipe">
<div dojoType="TreeNode" widgetId="node0" title="node0"></div>
<div dojoType="TreeNode" widgetId="node1" title="node1"></div>
<div dojoType="TreeNode" widgetId="node2" title="node2"></div>
</div>
both cases create a parent Tree with three tree nodes.
The following JavaScript methods can be used to query or change the dojo tree in some way or another.
| JavaScript Method | Description |
| addChild(child, index) | Adds child to the tree at the index given. If no index is given (it is an optional parameter), the child is appended to the end of the list of children. It is also important to note that the child you are adding can't already be a part of the tree, i.e. it must have a unique widgetId. |
| removeChild(child) | Remove the child from the tree. |
| initialize | Initialization protocol. Interprets arguments "selector" and "controller", etc.. TBD. |
| postCreate | Completes initialization of all tree nodes attached to this tree. |
| getInfo | Returns an object with properties "widgetId", this tree's widget ID; and "objectId", this tree's "objectId" property. Overridable. |
Similar to the above Dojo Tree JavaScript methods, the following JavaScript methods apply to the Dojo Tree Nodes
| JavaScript Method | Description |
| addChild(child, index) | Adds the given child to this node. You can apply this method to a node removed from another tree or a newly-created node, and this will adjust its display and tree relationships. |
| removeChild(child) | Removes the given child from this tree node. |
| setFolder | Asserts that this tree node is a folder, regardless of whether it has children currently or not. |
| expand | Show any children and mark the node as expanded. |
| collapse | Hide any children and mark the node as not expanded. |
| edit | Takes an object, which it treats as a collection of property-value mappings. Updates both widget and DOM state for properties |
When constructing a Dojo Tree you can set actions to occur when some event happens on a tree node:
| Events | Description |
| onTreeClick | Called when the expander icon is clicked. Event properties are "source": the node; "event" the triggering click event. Also publishes to tree.eventNames.treeClick. |
| onIconClick | Called when the node's icon is clicked. Event properties are "source": the node; "event" the triggering click event. Also publishes to tree.eventNames.iconClick. |
| onTitleClick | Called when the node's title is clicked. Event properties are "source": the node; "event" the triggering click event. Also publishes to tree.eventNames.titleClick. |
You can style the tree nodes by applying some css style tags or any other html tag. Some popular examples include:
title="<span style='color:red'>Node Title Text Goes Here "title="<a href='linkLocation.html'>Node Title Text Goes Here "title="<input type='checkbox'>Node Title Text Goes Here "This class, together with Tree, TreeSelector, and TreeNode, provide a tree widget with nodes that can be dynamically added, modified, and deleted. See the Complex Dojo Tree Example below to see the TreeRPCController in action.
| Property | Description |
| RPCUrl | String URL of a page that generates information for dynamic loading of tree nodes. "action=xxx" and node-specific information is always added in the request's query string. |
| DNDMode | Default "off". Controls the mode of drag-and-drop. Other possible modes are "onto" and "between". |
| eventNames | Object with properties select, deselect, collapse, expand, dblselect, move, remove. TODO: document these. |
| dragSources | TBD |
| dropTargets | TBD |
| errorHandler | Function to be called in case of errors in the internal I/O. Used exactly as an error handler for dojo.io.bind. |
| DNDController | ex. DNDController="create" |
| Property | Description |
| initialize | Sets up this controller's event names as widgetId+"/"+eventName. |
| Method | Description |
| subscribeTree(tree) | Subscribes this controller to the topics specified by the tree's eventNames: nodeCreate, treeClick, iconClick, and titleClick. They fire the controllers matching onNodeCreate, onTreeClick, onIconClick, and onTitleClick events. Normally called by the tree during its creation. |
| loadRemote(node, sync, callback, callObj) | Issues a request for loading the node's children. Requests the page specified by the RPCUrl with action=getChildren and data=xxx, where the value is the JSON representation of an object with two properties: "node" and "tree". The value of the "node" is the result of node.getInfo(), and the value of the "tree" is the result of tree.getInfo(). Passes the received JSON object to loadProcessResponse. Other parameters TBD. |
| loadProcessResponse(type, node, result, callback, callObj) | Type is supplied by "dojo.io.bind" as the response type. Node is the tree node. Result is the object created from the response JSON data. The JSON data is an array containing objects. This supplies each object as the information argument to dojo.widget.createWidget, and specifies the node's "widgetType" as the widget type for all new children. This adds the new children to the node and mark's the node as loaded. Finally if a callback is supplied, this calls it so that the callObj is "this", passing the node and new children as arguments. The callObj defaults to being the controller. |
| expand(node, callObj, callFunc, sync) | Normally called from onTreeclick. If the node's load state is "unchecked", calls loadRemote, with a callback function that expands the parent node when loading is done. Otherwise call's the node's expand method and publishes on the eventNames.expand topic. In all cases if there is a callFunc, calls it with callObj as "this" and the node as the one argument. |
| collapse(node) | If the node is expanded, calls node.collapse, then publishes on the eventNames.collapse topic. |
| select(node) | Called from onTitleClick. Calls the node's "markSelected" method, records it as the tree selector's selectedNode, and publishes on the controller's eventNames.select topic. |
| deselect(node) | Call's the node's unMarkSelected method, sets the selector's selectedNode to null, and publishes on the eventNames.deselect topic. |
These events are set up by the subscribeTree method.
| Event | Description |
| onTreeClick: | This expands or collapses the appropriate node. If the node has never before been expanded and has no children, this calls "loadRemote". |
| onIconClick: | Calls onTitleClick. |
| onTitleClick: | If the clicked node is the tree selector's seelectedNode, publishes on the controller's dblselect topic. If there is a previously selected node, calls this controller's deselect method on that node. Then calls this controller's "select" method on the clicked node. |
An Example of using a tree context menu would be:
<div dojoType="TreeContextMenu" toggle="none" contextMenuForWindow="false" widgetId="treeContextMenu"></div>
The Tree Context Menu is used when you'd like the users to be able to perform some action on the
tree such as adding a new node, etc. In which case you'd use a Context Menu to display what those
choices were to the user.

For this bare bones example we have three nodes in a dojo tree. The
second node is the only one which has child nodes. For this reason
you'll notice that it is the only node of the three that has a plug [+]
that allows the user to expand or collapse its' contents.
We'll now walk you through the code and what it takes to make this
example possible. The following code can be copied and pasted into an
html page to view the dojo tree widget in action. Don't forget you'll
need to download the dojo toolkit. For this example
we put the dojo source javascript under a directory named javascript.
<head>
<title>Simple Dojo Tree Example</title>
<script type="text/javascript" src="javascript/dojo.js"></script>
<script type="text/javascript">
dojo.require("dojo.widget.Tree");
dojo.require("dojo.widget.TreeSelector");
dojo.require("dojo.widget.TreeNode");
dojo.require("dojo.widget.TreeContextMenu");
</script>
</head>
<body>
<div dojoType="TreeSelector" widgetId="treeSelector"></div>
<div dojoType="Tree" widgetId="treeWidget" selector="treeSelector" toggler="wipe">
<div dojoType="TreeNode" widgetId="1" title="First node" isFolder="false"></div>
<div dojoType="TreeNode" widgetId="2" title="Second node">
<div dojoType="TreeNode" widgetId="2.1" title="Second node First Child"></div>
<div dojoType="TreeNode" widgetId="2.2" title="Second node Second Child"></div>
</div>
<div dojoType="TreeNode" widgetId="3" title="Third node" isFolder="false"></div>
</div>
</body>
</html>
As mentioned at the beginning of the article it is necesary to have the required dojo tree javascript imports defined which are the first few sections of this code. Next we must define the tree selector giving it a unique widgetId. That tree selector is then referenced with our dojoType=Tree tags. Give the Tree a cool toggler effect of wipe and we're ready to add in some nodes. There are tree direct nodes with widgetId's 1, 2, and 3 respectively. There is no root root node. Then tree node 2 has two children. That's it, you're off to a great start with discovering what dojo tree's can do. Next we'll jump into how Dojo Tree's can be used in an SOA Environment and give a complex example.
Moved this to before the complex example as it seems like the article will transition well between the two
This example is a little more complex than the SimpleDojoTreeExample just given. It uses java and a RPC
call to populate the nodes of the tree. You can download the source code to this example from the bottom of this article.
This example has a root node and three child nodes. When any of the
three child nodes are clicked a servlet will be called. The servlet
will then check to see which node was clicked and based on that it will
populate the children of that child. So, in the screen shot above, when
the user clicks on a color child they will see items that are of that
color. Under the Blue child the user will see a normal and a link node.
If the user clicks on Sky they will be directed to www.theSky.com.
Finally the Green children are unique because they call yet another jsp
page that loads inside of the current screen. So when you click on
Grass you'd see a message like the one displayed above. As soon as you
click on another child node (Cucumber or Frogs) that information will
replace the information that is currently displaying for Grass. This is
really useful if you'd like to load content specifc information onto a
section of the page based on the user clicking on a tree node.
Now we'll walk through the code that made this possible.
We'll start by looking that the index.html file. This is where the Dojo Tree is constructed. You'll notice that the required imports are placed at the beginning of the document as we described was necessary for the dojo trees. There are a few other JavaScript methods that we will come back to a little later. First let's just right into the body of the html:
<body>
<div dojoType="TreeRPCController" RPCUrl="GetAJAXTreeNodeServlet" widgetId="treeController"></div>
<div dojoType="TreeSelector" widgetId="treeSelector"></div>
<table class="treeTable" cellpadding="10">
<tr>
<td style="border:1px dashed black;">
<h4>Complex Dojo Tree</h4>
<div dojoType="Tree" selector="treeSelector" toggler="fade" widgetId="firstTree" controller="treeController">
<div dojoType="TreeNode" widgetId="1.1" title="RootNode" actionsDisabled="remove">
<!-- Below is where we put the Tree Nodes... -->
<div dojoType="TreeNode" widgetId="Red" title="Red" isFolder="true"></div>
<div dojoType="TreeNode" widgetId="Blue" title="Blue" isFolder="true"></div>
<div dojoType="TreeNode" widgetId="Green" title="Green" isFolder="true"></div>
</div>
</div>
</td>
</tr>
<tr><td id="partDetails"> </td></tr>
</table>
</body>
The first line of the code:
<div dojoType="TreeRPCController" RPCUrl="GetAJAXTreeNodeServlet" widgetId="treeController" ></div>
Is where the TreeRPCController is defined. This is important when using a servlet or other method
to populate the nodes of a dojo tree. The RPCUrl defines the name of this action that will be invoked.
In our case the GetAJAXTreeNodeServlet is called. The widgetId for this Tree Controller is "treeController"
so we'll need to use that widgetId to refer to this particular controller. The DNDController is for
specifying Drag and Drop Controllers. It is not present in this example because we have no enabled
the drag and drop functionality for this example.
Next we go on to define the tree selector:
<div dojoType="TreeSelector" widgetId="treeSelector"></div>
Nothing new here, just set the dojoType to be a TreeSelector and gave it a unique widgetId
The next few lines of code are just setting up a table where the dojo tree will reside in to give
it a visual appeal. Then we have the actual tree definition:
<div dojoType="Tree" selector="treeSelector" toggler="fade" widgetId="firstTree" controller="treeController">
You can see that the dojoType is a tree and that it points to the treeSelector defined above. The controller is the
"treeController" which our TreeRPCController that tells the tree which servlet to invoke.
Following that we'll need to create the Tree Nodes themselves. For this example the direct
children of the root node are hard coded like in our simple example:
<div dojoType="TreeNode" widgetId="1.1" title="RootNode">
<!-- Below is where we put the Tree Nodes... -->
<div dojoType="TreeNode" widgetId="Red" title="Red" isFolder="true"></div>
<div dojoType="TreeNode" widgetId="Blue" title="Blue" isFolder="true"></div>
<div dojoType="TreeNode" widgetId="Green" title="Green" isFolder="true"></div>
There is a RootNode with three children tree nodes. There is nothing fancy to the way they are defined
and used. The fancy stuff comes into play when you click on each of these nodes!
You might've noticed what seems to be an insignificant row on the bottom of the code:
<tr><td id="partDetails"> </td></tr>
This is where we'll stick an entirely different page after the children of the Green node are
clicked. You'll see exactly what we're talking about a little later. But first let's check out
the servlet, com.ibm.dojotree.GetAJAXTreeNodeServlet.java.
When any of the children nodes are clicked (Red, Blue, Green) the RPCUrl is followed to the
GetAJAXTreeNodeServlet class. There it's doGet method is called. Inside we see the following code
(you can follow along by downloading the example at the bottom of this article where all of the
source code is available):
String serializedNode = request.getParameter("data");
String resultNodes = "";
if (serializedNode.indexOf("Red") != -1){
ArrayList redThings = new ArrayList();
redThings.add("Cherries");
redThings.add("Strawberries");
resultNodes = this.getResultNodeString(redThings);
} else if (serializedNode.indexOf("Blue") != -1){
ArrayList things = new ArrayList();
things.add("<a href=http://www.thesky.com>Sky</a>");
things.add("Water");
resultNodes = this.getResultNodeString(things);
} else if (serializedNode.indexOf("Green") != -1){
String url = "<a onClick=getNodeDetails(\"Grass\")><span style=color:blue>Grass</span></a>";
ArrayList things = new ArrayList();
things.add("<a onClick=getNodeDetails(\"Grass\")><span style=color:blue>Grass</span></a>");
things.add("<a onClick=getNodeDetails(\"Cucumber\")><span style=color:blue>Cucumber</span></a>");
things.add("<a onClick=getNodeDetails(\"Frog\")><span style=color:blue>Frogs</span></a>");
resultNodes = this.getResultNodeString(things);
} else {
resultNodes = "[{title:'ERROR not a known color'}]";
}
/*
* For instance, one can call node.children = [{title:'node1'},{title:'node2'}].
* The objects will be set, but no widgets are created.
* You can also set children to nested array:
* node.children = [{title:'node1', children:[{title:'node2'}] }].
*/
response.getWriter().write(resultNodes);
As you can guess from reading the code there is a request parameter called data that has
all of the serialized information about which node was clicked to invoke the servlet. If you had clicked
Green, data would look like this:
{"node":{"widgetId":"Green","objectId":"","index":2,"isFolder":true},"tree":{"widgetId":"firstTree","objectId":""}}
Isn't that super cool?!? In our example we simply check to see if the name of the node appears
in the string representation of the node and if it does we formulate our response. Of course there are
better ways to do this but for example purposes this shows how the data request parameter is used.
Once we determine the node that was clicked we can return back personalized information about which
child nodes that node has. It should start to look familiar as it's basically setting the title of
each of the new children nodes so that they can be written back to the response. The comment
before we send back the response explains how the string should be formatted. We also include
a handy helper method that takes an ArrayList of string titles and returns a string representing
all of the arraylist as siblings.
Once these results are returned back to the user there is still one last sweet feature that we
added in just for kicks and giggles. When you click on one of the Green node's children some information
is displayed on the bottom of the screen. How did we do that? Well, that's just plain old AJAX.
If you'll recall from the doGet method of the servlet we added an action to all of the Green's children
things.add("<a onClick=getNodeDetails(\"Grass\")><span style=color:blue>Grass</span></a>");
onClick=getNodeDetails("Grass"). We promised you we'd get back to the unused javascript methods in
index.html and now we will.
var strURL = 'nodeDetails.jsp?item=' + node;
var xmlHttpReq = false;
var self = this;
// Mozilla/Safari
if (window.XMLHttpRequest) {
self.xmlHttpReq = new XMLHttpRequest();
}
// IE
else if (window.ActiveXObject) {
self.xmlHttpReq = new ActiveXObject("Microsoft.XMLHTTP");
}
self.xmlHttpReq.open('GET', strURL, true);
self.xmlHttpReq.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
;
self.xmlHttpReq.onreadystatechange = function() {
if (self.xmlHttpReq.readyState == 4) {
var divElement = document.getElementById('partDetails');
divElement.innerHTML = self.xmlHttpReq.responseText;
}
}
self.xmlHttpReq.send('');v
}
This is some basic AJAX code here but it's simply calling the nodeDetails.jsp page with the item
request parameter set to equal the name of the node that was passed into the method. Then it's placing
the results from the nodeDetails.jsp page directly into the index.html document at the id partDetails
(remember when we said this is where the information would be placed!!).
The nodeDetails.jsp page says:
<html>
<head>
<title>Part Details</title>
<link rel=stylesheet href="css/general.css" type="text/css">
</head>
<body>
<% String item = request.getParameter("item"); %>
<h3><font color="green">You just clicked on a <%= item %> item! Try clicking again</font></h3>
</body>
</html>
Pretty Exciting Stuff!!
There are endless possibilities on what can be done with a dojo tree. Hopefully this article has piqued your interest such that you're off right now spicing up your website with the help of our two examples.
Add the downloads for this article here
AjaxTree
Copyright AjaxTree All Rights Reserved