I would like to know how ot update the data of the dojo.dijit.tree component dynamically. At the moment I'm creating the tree using dojo.data.ItemFileReadStore and dijit.tree.ForestStoreModel. Once I create the tree, I would like to reload it periodically with new JSON data.
This is how I create the tree at the moment:
<div dojoType="dojo.data.ItemFileReadStore" jsId="myStore" url=getJSONResult></div>
<div dojoType="dijit.tree.ForestStoreModel" jsId="myModel" store="myStore" query="{type:'cat'}" rootId="myRoot" rootLabel="Data" childrenAttrs="children"></div>
<div dojoType="dijit.Tree" model="myModel" labelAttr="sname" label="Data" />
Thanks in advance.
Explicitly you "can't", but that doesn't mean you can't hack things to pieces and die trying.
refreshTree : function(){
dijit.byId("myTree").dndController.selectNone(); // As per the answer below
// Credit to this discussion: http://mail.dojotoolkit.org/pipermail/dojo-interest/2010-April/045180.html
// Close the store (So that the store will do a new fetch()).
dijit.byId("myTree").model.store.clearOnClose = true;
dijit.byId("myTree").model.store.close();
// Completely delete every node from the dijit.Tree
dijit.byId("myTree")._itemNodesMap = {};
dijit.byId("myTree").rootNode.state = "UNCHECKED";
dijit.byId("myTree").model.root.children = null;
// Destroy the widget
dijit.byId("myTree").rootNode.destroyRecursive();
// Recreate the model, (with the model again)
dijit.byId("myTree").model.constructor(dijit.byId("myTree").model)
// Rebuild the tree
dijit.byId("myTree").postMixInProperties();
dijit.byId("myTree")._load();
},
This will refresh your Tree.
Here's a problem with Layke's solution (which otherwise does work) found by pre-production testing for a commercial website.
Case 1:
- Create & populate a tree.
- Click on a node to select.
- Execute refreshTree as in Layke's solution.
- Click on a node, get error "this.labelNode is undefined".
Now start again, case 2:
- Create & populate a tree.
- Click on a node to select.
- Ctrl-click on the previously selected node.
- Execute refreshTree as in Layke's solution.
- Click on a node, no error.
The stored selection references to the first selection are being used to undo the
selection attributes (background color, etc.) when the second selection is made.
Unfortunately, the referred-to objects are now in the bit-bucket. The modified code
appears to be production-ready, i.e. hasn't failed any pre-production tests.
The solution is to put:
Tree.dndController.selectNone();
prior to first line of Layke's refreshTree solution above.
In response to meta suggestions, here it is:
refreshTree : function() {
// Destruct the references to any selected nodes so that
// the refreshed tree will not attempt to unselect destructed nodes
// when a new selection is made.
// These references are contained in Tree.selectedItem,
// Tree.selectedItems, Tree.selectedNode, and Tree.selectedNodes.
Tree.dndController.selectNone();
Tree.model.store.clearOnClose = true;
Tree.model.store.close();
// Completely delete every node from the dijit.Tree
Tree._itemNodesMap = {};
Tree.rootNode.state = "UNCHECKED";
Tree.model.root.children = null;
// Destroy the widget
Tree.rootNode.destroyRecursive();
// Recreate the model, (with the model again)
Tree.model.constructor(dijit.byId("myTree").model)
// Rebuild the tree
Tree.postMixInProperties();
Tree._load();
}
Thanks for this function, works great in my tree.
A notice to those who are new to dojo (like me)... After creation of the tree, it is needed to extend the tree with the refresh function:
dojo.extend(dijit.Tree, {
refresh: function() {
this.dndController.selectNone();
//...
}
});
Then you can call the function with:
dijit.byId('myTree').refresh();
Updating your store will automatically update your tree!
- You need a FileWriteStore, which gives you the ability to modify your data.
- Use the store to fetch the items you want to update via query.
- Update each item returned.
Then save the store and the tree will update.
FileWriteStore.fetch({
query: { color: "red" },
onComplete: function(items){
for (var i = 0; i < items.length; i++){
FileWriteStore.setValue(items[i], "color", "green");
}
FileWriteStore.save();
}
});
Layke's solution did not work for me. I am using dojo 1.9.1. My store is of type "ItemFileWriteStore" and the model of type "TreeStoreModel".
myStore = new ItemFileWriteStore({
url : "../jaxrs/group/tree"
});
itemModel = new TreeStoreModel({
store : myStore,
query : {
id : "0"
}
});
parser.parse();
This works for me:
var tree = dijit.byId('myTree');
tree.dndController.selectNone();
tree._itemNodesMap = {};
tree.model.root = null;
tree.model.store.clearOnClose = true;
tree.model.store.urlPreventCache = true;
tree.model.store.revert();
tree.model.store.close();
tree.rootNode.state = "UNCHECKED";
if (tree.rootNode) {
tree.rootNode.destroyRecursive();
}
tree.postMixInProperties();
tree._load();
While going through these answers I've built my own method to update specific nodes once at a time and NOT need the refresh.
_refreshNodeMapping: function (newNodeData) {
if(!this._itemNodesMap[newNodeData.identity]) return;
var nodeMapToRefresh = this._itemNodesMap[newNodeData.identity][0].item;
var domNode = this._itemNodesMap[newNodeData.identity][0].domNode;
//For every updated value, reset the old ones
for(var val in newNodeData)
{
nodeMapToRefresh[val] = newNodeData[val];
if(val == 'label')
{
domNode.innerHTML = newNodeData[val];
}
}
}
Not supported at present. See here.