PDA

View Full Version : Load a tree on demand with a "external" store



csanchezr85
8 Jul 2012, 11:30 PM
Hello,

I want to load the items of a tree on demand but with an "external" store. I explain myself: I have a class responsible to communicate with server. This class is the unique which can make calls to server and this class is the one which gice the data to my tree. Due to the high volume of data to load I want to load the tree items on demand but I have a problem that I haven't solved yet:
- Nodes that are not leafs doesn't render the expand icon: 36936. "Llobregat Nord" and "Barcelona Sud" must have the "SGAB" expand icon because these nodes really have children although they have not been brought from server yet. I'd like that the expand icon would be drawn and when user clicks on it the children are loaded from the store of the class which calls to server. I have tried this loading dynamically the childrend and adding them to the selected node of the tree store but this solution doesn't works well.

Has anyone the same issue or similar? Thanks in advance.

Izhaki
9 Jul 2012, 2:02 AM
Please provide the JSON you return from the server.

You should get what you want by setting leaf to false and loaded to false.

csanchezr85
9 Jul 2012, 4:27 AM
Thanks for your reply!

From server I receive raw data so I need to build the node structure in the client. This is the structure I used previously to your reply:



node = {
text: objectHierarchy.Name,
qtip: qtip,
qtitle: qtitle,
expanded: false,
children: listNodes,
iconCls: icon,
expandable: true,
leaf: false,
guid: objectHierarchy.Id,
idTimeSerieRaw: objectHierarchy.IdTimeSerieRaw,
latitude: objectHierarchy.Latitude,
longitude: objectHierarchy.Longitude
};


The last four properties have been added by my own interest so do not worry about them.

I really forgot to add the "loaded: false" attribute. But after add this the tree still didn't was drawn correctly. I have had to remove "children: listNodes". Obviusly listNodes is an empty list of children, because in every call to server I only bring one level of children. After these two changes the expand icons are visible. Thank for this!

Now I've implemented an action on the "expand" event of every node. The code of the callback function that fires when a node is expanded is:



var nodeRoot = createHierarchyRootNode(json, true);

var store = Ext.create('Ext.data.TreeStore', {
fields: ['text', 'guid', 'latitude', 'longitude', 'idTimeSerieRaw'],
root: nodeRoot
});

nodeRootGlobal = hierarchy.tree.getRootNode();
nodeRoot.expanded = true;
var anchorNode = nodeRootGlobal.findChild('text', nodeRoot.text, true);
store.getRootNode().data.expanded = true;
nodeRootGlobal.replaceChild(store.getRootNode(), anchorNode);
nodeRootGlobal.expanded = true;
//Set the new node
hierarchy.tree.setRootNode(nodeRootGlobal);


Basically what I do is to bring data and build a new store from the received data (the root of the subhierarchy is the node we want to expand). After this we search the selected node in the original nodes structure of the tree and replace this node by the new one. Finally I set the new complete structure to the tree.

This works correctly the first time I expand a node but the next actions over the tree make raise some errors, even its behaviour isn't the expected, e.g., I select another node and the expand event is executed twice or three times, or the listener for the expand event stops to work...

The event assignment is made in the creation of the first node:


nodeRootGlobal.on('expand', function (node, opts) {
createSubhierarchy(node.data.guid);
});


Is there any way to make it "better" or correctly??

csanchezr85
12 Jul 2012, 5:00 AM
Well, I have modified a little the algorithm and it seems to be a little less wrong. The callback function after retreive the items from server:


var json = (typeof result.data) == k_STRING ? eval('(' + result.data + ')') : result.data;
var nodeRoot = createHierarchyRootNode(json, true);
nodeRoot.expanded = true;


var store = Ext.create('Ext.data.TreeStore', {
fields: ['text', 'guidItem', 'guidAsset', 'latitude', 'longitude', 'idTimeSerieRaw'],
root: nodeRoot
});


var n = hierarchy.tree.getStore().getRootNode();
var anchorNode = n.findChild('text', nodeRoot.text, true);
n.replaceChild(store.getRootNode(), anchorNode);

In "nodeRoot" I have the new structure to render, after I create a new store and search for the expanded node. Then I replace the old selected node by the root node of the new store created (which is equal to selected node but with the difference that the new has children).

Also I have changed the listener assignment:


var treeStore = hierarchy.tree.getStore();
treeStore.on('expand', function (node, opts) {
if (node.data.guidAsset != k_EMPTY_STR) {
if (!node.hasChildNodes()) {
setTreeBusy(k_DIV_HIERARCHY_BUSY, k_CSS_CLASS_BUSY_HIERARCHY);
createSubhierarchy(node.data.guidAsset);
}
}
});


Now I apply the listener to the store against to apply to rootNode although the effect is the same.

The first time all works correctly but the next time I try to expand a node the expand event is executed twice and the tree doesn't render correctly and after this the "expand" event doesn't fire anymore. I'm bofuscated with this!!

csanchezr85
13 Jul 2012, 3:14 AM
I've finally solved this issue!! As was blocked with this I erased all I had made and started again:



function (result) {
var json = (typeof result.data) == k_STRING ? eval('(' + result.data + ')') : result.data;
var nodeRoot = createHierarchyRootNode(json, false);
nodeRoot.expanded = true;


var childrenArray = [];
var n = hierarchy.tree.getStore().getRootNode();
if (nodeRoot.children != null) {
for (x = 0; x < nodeRoot.children.length; x++) {
var node = nodeRoot.children[x];
var nodeStore = hierarchy.tree.getStore().getRootNode().createNode(node);
nodeStore.loaded = node.loaded;
childrenArray.push(nodeStore);
}
}




var anchorNode = n.findChild('text', nodeRoot.text, true);
if (childrenArray != null && childrenArray.length > 0) {
anchorNode.appendChild(childrenArray);
anchorNode.eachChild(function (node) {
if (!node.loaded) {
node.data.loaded = false;
}
});
}
hierarchy.tree.getStore().sync({
scope: this,
success: function () {
//Remove the busy div
setTreeNoBusy(k_DIV_HIERARCHY_BUSY, k_CSS_CLASS_BUSY_HIERARCHY);
},
failure: function () {
//Remove the busy div
setTreeNoBusy(k_DIV_HIERARCHY_BUSY, k_CSS_CLASS_BUSY_HIERARCHY);
}
});




}


Now I create a NodeInterface object from my node primitive object and then I append it to the selected node. Finally I call to sync method to sync the view with the store and it works fine: all the nodes are drawn correctly, every expand event is fired correctly...

But I have to mark two points:
- I think that the "appendChild" of the NodeInterface class has a little bug: when I add a node which has its "loaded" property to false to the selected item after append it, if we watch the children of the selected item, the appended node has changed its "loaded" property to true.
-I have also a lot of problems debugging the above algorithm in mozilla firebug: while I was debugging, I have a lot of problems with the expand children event because many times they weren't rendered. After deleting all breakpoints in firebug this problem doesn't appear anymore.