I am trying to implement a cross domain, lazy loading tree using the Dojo toolkit. So far I have the top level nodes displaying correctly, but on clicking the expando I get a "deferred has already been resolved" error and I'm not sure why. I can see that the fetch method seems to be working by looking at the firebug network tab. I think my problem is within my _processResults method, perhaps something to do with the defining of the _loadObject within it...
I feel like I should know Dojo better given all the time I've spent trying to understand it. But alas, its quite a beast... I've seen some mention of JSONP and lazyloading not working in one of the sitepen blogs (http://www.sitepen.com/blog/2008/06/25/web-service-data-store/ ), but it doesn't mention why it shouldn't be possible other than JSONP being asyncronus. If Dojo is going to just stuff incoming json data into the store, I don't understand why that should matter.
Perhaps it has to do with my formating of the data - another example on sitepen (http://www.sitepen.com/blog/2010/01/27/efficient-lazy-loading-of-a-tree/) using the jsonreststore doesnt load an item until you expand a node, whereas my format loads the item but doesnt load the children nodes until you expand it...
Without further ado, here is ta codez...
<script type="text/javascript">
dojoConfig = {
parseOnLoad: true,
isDebug: true,
usePlainJson: true
};
</script>
<script type="text/javascript" src="scripts/dojo_16/dojo/dojo.js"></script>
<script type="text/javascript">
dojo.require("dojo.parser");
dojo.require("dojo.io.script");
dojo.require("dojox.rpc.Service");
dojo.require("dojox.data.ServiceStore");
dojo.require("dijit.tree.ForestStoreModel");
dojo.require("dijit.Tree");
dojo.addOnLoad(function(){
var mySmd = {
"SMDVersion": "2.0",
"id": "http://urlbehindfirewall/testtree/",
"description": "This is the service to get to the finder app backend data",
transport: "JSONP",
envelope: "URL",
additionalParameters: true,
target: "http://urlbehindfirewall/testtree/",
services: {
"getChildrenNodes": {
"target": "getChildrenNodes.php",
parameters: [
{ name: "nodeId", type: "integer"}
]
}
}
};
var myService = new dojox.rpc.Service(mySmd);
var myStoreParams = {
service : myService.getChildrenNodes,
idAttribute : "Node_Id",
labelAttribute : "Display_Name",
_processResults: function(results, def){
var _thisStore = this;
for(i in results){
results[i]._loadObject = function(callback){
_thisStore.fetch({
query: { nodeId: this.Node_Id },
onItem: callback
});
delete this._loadObject;
};
}
return {totalCount: results.length, items: results};
}
};
var myStore = new dojox.data.ServiceStore(myStoreParams);
//create forestTreeModel
var treeModelParams = {
store: myStore,
deferItemLoadingUntilExpand: true,
childrenAttrs: ["Children_Nodes"],
rootId : 1,
query: 1
};
var treeModel = new dijit.tree.ForestStoreModel(treeModelParams);
var myTree = new dijit.Tree({
model: treeModel,
id: "myTree",
showRoot: false
});
dojo.byId("treeContainer").appendChild(myTree.domNode);
myTree.startup();
});
</script>
And here is an example of the json data structure: unfortunately the service is behind a network firewall currently... i will work on putting up a public version to demonstrate in a bit. Meanwhile, this is the response for searching on the root node, node 1:
[
{
"Node_Id":"2",
"Display_Name":"LeftNode:2",
"Secondary_Names":"Parent:1",
"Obi_Id":"10002",
"Children_Nodes":[
],
"Has_Children":true,
"Child_Node_Ids":[
"5",
"6",
"7",
"8"
]
},
{
"Node_Id":"3",
"Display_Name":"Middle Node:3",
"Secondary_Names":"Parent:1",
"Obi_Id":"10003",
"Children_Nodes":[
],
"Has_Children":true,
"Child_Node_Ids":[
"9",
"10"
]
},
{
"Node_Id":"4",
"Display_Name":"Right Node:4",
"Secondary_Names":"Parent:1",
"Obi_Id":"10004",
"Children_Nodes":[
],
"Has_Children":true,
"Child_Node_Ids":[
"11",
"12"
]
}
]
Expanding any of the above nodes would then get the children of that node - so 2 would get the node array of 5,6,7,8 . (It may not be necessary to have the Child_Node_Ids and Children_Nodes for the current implementation, but shouldn't be breaking anything no?)
So I'm sure eyes are glazing by now, to restate the issue - what is creating this "deferred has already been resolved" error? Is lazy loading in a tree possible with JSONP? Would a different json structure solve my lazy loading problems? Is it possible to reformat my data within dojo so that it works? (I thought that was the point to the _processResults method... ) Are there any publicly accessible tree dataservices out there to practice on?
Thanks everyone!