The "How to display tree with expanded nodes?" question raised on our forum and it seems that there is no easy answer on this question. Here I want to post my investigation and describe my solution on this.
The current release of the Dojo Toolkit contains a tree widget, which displays hierarchy of nodes in well-known form with collapsible nodes. The tree widget works together with the Store component that may be considered as adapter or common interface to data. Being placed on the page, the tree widget queries its store by calling asynchronous fetch() method to get the list of root nodes. Because the method is asynchronous, the nodes created in callback function, which is passed into the method as argument.
Here are some key code fragments that related to the described process:
// Declaration of dijit.TreeBase
dojo.declare(
"dijit._TreeBase",
[dijit._Widget, dijit._Templated, dijit._Container, dijit._Contained],
{
...
setChildren: function(childrenArray){
...
// Create _TreeNode widget for each specified tree node
dojo.forEach(childrenArray, function(childParams){
var child = new dijit._TreeNode(dojo.mixin({
tree: this.tree,
label: this.tree.store.getLabel(childParams.item)
}, childParams));
this.addChild(child);
nodeMap[this.tree.store.getIdentity(childParams.item)] = child;
}, this);
...
},
...
}
// Declaration of dijit.Tree
dojo.declare(
"dijit.Tree",
dijit._TreeBase,
{
...
postCreate: function(){
...
// start the controller, passing in the store
this._controller = new dijit._tree.DataController(
{
store: this.store,
treeId: this.id,
query: this.query,
childrenAttr: this.childrenAttr
}
);
// The following line causes calling of DataController.onAfterTreeCreate
this._publish("afterTreeCreate");
},
...
}
// Declaration of dijit._tree.DataController
dojo.declare(
"dijit._tree.DataController",
dijit._tree.Controller,
{
onAfterTreeCreate: function(message){
...
function onComplete(/*dojo.data.Item[]*/ items){
var childParams=dojo.map(items,
function(item){
return {
item: item,
isFolder: _this.store.hasAttribute(item, _this.childrenAttr)
};
});
_this._itemNodeMap = tree.setChildren(childParams);
}
this.store.fetch({ query: this.query, onComplete: onComplete });
},
...
}
Let's back to the question, asked below: how to display tree with expanded nodes? In other words, we want to show tree with some nodes already opened, not only collapsed root nodes. What comes in mind first is to open nodes in onload event of the page or in startup event of the tree but these ideas are wrong. They are wrong because tree nodes may not be loaded nor during onload event nor when any other startup event is raised. And unfortunately, there no any other event we can subscribe to open a node. There is no onSetChildren, no onCreateNode, no some other event which occurs when the tree data is available.
Investigating alternatives, I consider to extend the Tree widget with the requested functionality. I added the "path" property that contains a path of identity values to a node that should be expanded and expand nodes in the addChild method as follows:
dojo.declare(
"AdvancedTree",
dijit.Tree,
{
path: '',
getPath: function (node, separator) {
var path = separator;
do {
path = separator + this.tree.store.getIdentity(node.item) + path;
node = node.getParent();
} while ('dijit._TreeNode' == node.declaredClass);
return path;
},
expander: function (node)
{
if (node.declaredClass == 'dijit._TreeNode') {
dojo.connect(node, 'addChild', this, 'expander');
}
var nodePath = this.getPath(node, '/');
if ((this.path.substr(0, nodePath.length) == nodePath) && node.isFolder) {
this._controller._expand(node);
}
},
addChild: function ()
{
dijit.Tree.prototype.addChild.apply(this, arguments);
this.expander(arguments[0], 1);
}
});
The following HTML fragment demonstrates how to place the AdvancedTree widget on a page and specify which node should be expanded:
<div dojoType="dojo.data.ItemFileReadStore" jsId="continentStore"
url="dijit/tests/countries.json"></div>
<div dojoType="AdvancedTree" id="mytree" jsId="mytree"
store="continentStore" query="{type:'continent'}"
labelAttr="name" typeAttr="type" path="/North America/Canada/Ottava">
</div>
Comments
iT works!
Whoo hoo, your a genius Alex, thanx : - )
Mike
i don't have dijit._tree.Controller in dojo package
hi there
i have downloaded the latest dojo 1.0.2 and there is no dijit._tree.Controller int it, what dojo package you where using ?