Closed aramk closed 10 years ago
The with the next cbtree release (1.0) each node will have a depth
property. With releases 0.9x you could use the node's indent
property instead. Be aware though that if the tree property showRoot
is set to false
the indent of the root node will be -1 and the immediate children of the root get indent 0.
Thanks for that! I ended up implementing a depth property pretty easily since I already had a method to recursively find all parents and children of an item. I'll post it here for anyone who finds it useful:
// Inside a Dojo class called _TreeMixin:
/**
* @param item - A store item.
* @returns {dojo.Deferred} Gets all parents and all children recursively.
*/
getAllParentsAndChildren: function(item) {
var results = {
parents: [],
children: []
},
df = new Deferred();
this.getAllParents(item).then(lang.hitch(this, function(parents) {
results.parents = parents;
var index = 0;
for (; index < results.parents.length; index++) {
parents[index].index = index;
}
item.index = index;
results.children = this.getAllChildren(item);
df.resolve(results);
}), function(err) {
df.reject(err);
});
return df;
},
/**
* @param item - A store item.
* @returns {dojo.Deferred} A promise which contains an array of all recursive parents of the
* item.
*/
getAllParents: function(item) {
var getParent = lang.hitch(this, function(someItem) {
var df = new Deferred(),
reject = function(err) {
df.reject(err);
};
this.model.getParents(someItem).then(lang.hitch(this, function(parents) {
var dfs = [],
allParents = [];
array.forEach(parents, function(parent) {
dfs.push(getParent(parent));
}, this);
all(dfs).then(lang.hitch(this, function(manyParents) {
manyParents.push(parents);
array.forEach(manyParents, function(someParents) {
array.forEach(someParents, function(aParent) {
if (!this.isRoot(aParent)) {
allParents.push(aParent);
}
}, this);
}, this);
df.resolve(allParents);
}), reject);
}), reject);
return df;
});
return getParent(item);
},
/**
* @param item - A store item.
* @returns {Array.<Object>} A promise which contains an array of all recursive children of the
* item.
*/
getAllChildren: function(item) {
var allChildren = [];
var toVisit = ([]).concat(item);
while (toVisit.length > 0) {
var item = toVisit.pop();
this.model.getChildren(item, lang.hitch(this, function(children) {
// Opted not to use concat() since it recreates the entire array.
array.forEach(children, function(child) {
var index = item.index;
if (index !== undefined) {
child.index = index + 1;
}
allChildren.push(child);
toVisit.push(child);
}, this);
}));
}
return allChildren;
}
As a FYI:
If you use a cbtree Hierarchy or Object store you could use the store extension Ancestry
which offers all the functionality you are looking for. The extension has methods like: getAncestors()
or getDescendants()
.
The extension can be found @ cbtree/store/extensions/Ancestry
Thanks for that, definitely a better option than reinventing the wheel!
Be aware though, accessing the store directly from the tree violates the Model-View-Controller pattern, which may be fine for your application. Also, the store's getAncestors()
and getDescendants()
methods rely on the store hierarchy which may be different from the tree hierarchy.
Consider the following:
var carData = [
{ name:"Cars" ,parent: null , type:"toys" },
{ name:"Audi" ,parent:"Cars", type:"factory" },
{ name:"BMW" ,parent:"Cars", type:"factory" },
{ name:"A3" ,parent:"Audi", type:"sedan" },
{ name:"Q7" ,parent:"Audi", type:"suv" },
{ name:"M3" ,parent:"BMW" , type:"sedan" },
{ name:"535" ,parent:"BMW" , type:"sedan" },
{ name:"750" ,parent:"BMW" , type:"sedan" },
];
...
var myStore = new Hierarchy({data: carData, ... });
var myModel = new ForestStoreModel({store: store, query: {type:"sedan"}, ... });
In this case the tree will show "A3", "M3", "535" and "750" as children of the tree root. whereas:
var parents = store.getAncestors("A3");
returns the objects "Audi" and "Cars", not the tree root., and
var parents = store.getAncestors("535");
returns the objects "BMW" and "Cars"
The same applies when using the model getParents()
method. See also: Store Root versus Tree Root
Hope this helps.
Ah thanks for that clarification!
Is there any way to get the depth of an item in the tree? The
$root$
node would be 0 and the immediate children would be 1 etc. I could write the traversal function using the model'sgetParents()
to get the current item's depth and use it withgetChildren()
to determine the children depths.