PDA

View Full Version : Ext.ux.tree.JsonTreeLoader



MuratCorlu
25 Jan 2010, 6:07 AM
Hi everyone!

When I was trying to use TreePanel, I needed some extra works about parsing of dynamic tree data. I'm using JSON that created with PHP. But I wanted to change structure of TreeNode attributes. For example, I don't like send a "leaf" attributes because of I already knew "children" attribute.

So, I implemented a small plugin named JsonTreeLoader. Maybe somebody needs a plugin like this.

Plugin code:


Ext.ns('Ext.ux.tree');

/**
* @class Ext.ux.tree.JsonTreeLoader
* @extends Ext.tree.TreeLoader
* <p>A TreeLoader that gives chance to specify a root path of data source, change node attributes
* names.</p>
*
* Creates a new JsonTreeloader.
* @param {Object} config A config object containing config properties.
* @author Murat Corlu
* @link http://muratcorlu.com
*/


Ext.ux.tree.JsonTreeLoader = Ext.extend(Ext.tree.TreeLoader, {

// Nodes array root path
root:undefined,

// To specify different attribute names for TreeNode
attrNames:{},

// You don't have to send a leaf attribute. If your node has children, leaf is false, otherwise true
// You can set this property false to use standart way
leafFromChildrenCount: true,

// private. to handle children attribute name
childrenAttrName: 'children',

// private override
processResponse : function(response, node, callback){
var data = Ext.decode(response.responseText);

// if root property set then use given path as root
if (this.root) {
var rootPath = this.root.split('.');

Ext.each(rootPath, function(path) {
data = data[path];
});
}

// get custom children attribute name
for(customName in this.attrNames) {
if (this.attrNames[customName] = 'children') {
this.childrenAttrName = customName;
}
}
try{
node.beginUpdate();
node.appendChild(this.parseData(data));
node.endUpdate();

if(typeof callback == "function"){
callback(this, node);
}
}catch(e){
this.handleFailure(response);
}
},

// private
parseData : function(data) {
var nodes = [];
Ext.each(data, function(n){
var treeNode = this.createNode(n);

if(n[this.childrenAttrName]){
var child = this.parseData(n[this.childrenAttrName]);
treeNode.appendChild(child);
}
nodes.push(treeNode);
}, this);

return nodes;
},


// private override
createNode : function(node){

this.defaultProcessAttributes(node);

// Make optional manipulations if it set
this.processAttributes(node);

return Ext.ux.tree.JsonTreeLoader.superclass.createNode.call(this, node);
},

defaultProcessAttributes : function(attr) {
// Replace custom attributes with standart ones
for(item in attr) {
if (this.attrNames[item]) {
attr[this.attrNames[item]] = attr[item];
attr[item] = undefined;
}
}
// Automatic leaf calculation
if(this.leafFromChildrenCount) {
attr.leaf = attr.children ? !(attr.children.length > 0) : true;
}
},

// override this method if you want
processAttributes : Ext.emptyFn
});

Usage:

An example of sent data from PHP:


{
"success":true,
"data": [{ // I can use treenodes array at different path from root
"id":12,
"textData":"First Item", // I used textData key instead of text
"items":[{ // I used items key instead of children
"id":2312,
"textData":"Leaf Item" // I don't have to use leaf key
}]
}]
}

And Ext side:


new Ext.tree.TreePanel({
........
loader: new Ext.ux.tree.JsonTreeLoader({
dataUrl:"http://example.com/api/",
root:'data', // Setting rootpath
attrNames:{
'textData':'text', // I say: use "textData" for "text"
'items':'children' // and use "items" instead of "children"
}
}),
.......

I hope it will help you...

moegal
18 Feb 2010, 5:48 AM
this looks very interesting, I will try it today.

Thanks, Marty

moegal
18 Feb 2010, 12:57 PM
I am having some problems with the treeloader. When I change textData to text in the json it mostly works.

Shouldn't the attributes look more like:



attrNames:{
text: 'textData', // I say: use "textData" for "text"
children: 'items' // and use "items" instead of "children"
}


You currently have:



attrNames:{
'textData':'text', // I say: use "textData" for "text"
'items':'children' // and use "items" instead of "children"
}



Thanks, Marty

MuratCorlu
31 Mar 2010, 6:16 AM
Hi Marty,

Your feedback is interesting. attrNames property get attritbute name mapping with a structure "newAttributeName : standartName". I couldn't realize your problem. Sorry...

By the way, I updated the code. I added ability to mapping root path nested. So you can give rootPath like "data.list.categories". This will get response's data.list.categories property.

Murat

Animal
31 Mar 2010, 6:28 AM
If you use different property names in the JSON to that which the TreeNode constructor uses, then simply configure your own implementation of createNode into the loader.

http://www.extjs.com/deploy/dev/docs/?class=Ext.tree.TreeLoader&member=createNode

MuratCorlu
31 Mar 2010, 6:45 AM
If you use different property names in the JSON to that which the TreeNode constructor uses, then simply configure your own implementation of createNode into the loader.

http://www.extjs.com/deploy/dev/docs/?class=Ext.tree.TreeLoader&member=createNode

That seems good. But I couldn't understand exactly how to use it. How can I use "items" instead of "children" with this method? Can you give an example?

Animal
31 Mar 2010, 7:16 AM
create the new node using children, but use the items property.?

MuratCorlu
31 Mar 2010, 7:30 AM
Like this?:


createNode: function(attr) {
attr.children = attr.items;
return Ext.tree.TreeLoader.prototype.createNode.call(this, attr)
}

I couldn't run this truely.

My data store sends a json like this:


{
"success":true,
"data": [{
"id":1,
"text":"Main menu",
"items":[{
"id":11,
"text":"Sub menu"
}]
}]
}

So, data store don't give mi a leaf attribute. And give me child attributes with "items" property. Now, I want to show a treepanel using this store.

Sorry for my poor English..