View Full Version : Parent based TreeLoader

25 Oct 2007, 6:19 AM
During development I found the leaf method doesn't fit our needs. I've built a custom treeloader which uses a parent base hierarchy method. It performs a single call to the server to retrieve the full json tree. It then loads the root nodes. The child nodes are not loaded into the tree until it is required. This allows us to minimize our server calls, simplify our server side work and optimize the user interactions.



Ext.ux.tree.ParentLoader = function(config) {
this.baseParams = {};
this.requestMethod = "POST";
Ext.apply(this, config);
"beforeload" : true,
"load" : true,
"loadexception" : true

Ext.extend(Ext.ux.tree.ParentLoader, Ext.tree.TreeLoader, {

getChildren: function(parent){
var items = new Array();
this.store.each(function(rec) {
if(rec.get('parent')==parent) items[items.length]=rec;
return items;

hasChildren: function(id){
return (this.getChildren(id).length > 0);

addChildren: function(parent) {
Ext.each(this.getChildren(parent.attributes.id), function(rec){
var attr = {};
if(this.baseAttrs) Ext.applyIf(attr, this.baseAttrs);
if(this.applyLoader !== false) attr.loader = this;
Ext.each(this.dataFields, function(item){
attr[item] = rec.get(item);
var node =(this.hasChildren(attr.id)?
new Ext.tree.AsyncTreeNode(attr):
new Ext.tree.TreeNode(attr));

load : function(node, callback){
if(!!this.store) {
if(typeof callback == "function") callback();
this.requestData(node, callback);

requestData : function(node, callback){
if(this.fireEvent("beforeload", this, node, callback) !== false){
this.store = new Ext.data.JsonStore({
url: this.dataUrl,
root: this.dataRoot,
fields: this.dataFields
this.store.on('load', this.handleResponse.createDelegate(this, [node, callback], 1));
this.store.on('loadexception', this.handleFailure.createDelegate(this, [node, callback], 1));
if(typeof callback == "function")callback();

processResponse : function(response, node, callback){
try {
this.load.call(this, node, callback);

handleResponse : function(response, node, callback){
this.transId = false;
this.processResponse(response, node, callback);
this.fireEvent("load", this, node, response);

handleFailure : function(response, node, callback){
this.transId = false;
this.fireEvent("loadexception", this, node);
if(typeof callback == "function") callback(this, node, response);


Sample Json:



var new Ext.tree.TreePanel({
loader: new Ext.ux.tree.ParentLoader({
dataUrl: '/load-pages.aspx',
dataRoot: 'pages',
dataFields: ['id','parent','text','url']
title: 'Site Map',
containerScroll: true,
rootVisible: false,
listeners: {
dblclick: function(node){
var root = new Ext.tree.AsyncTreeNode({text: 'Root', draggable:false, id:'0', url:'/', expanded:true});

I hope someone else finds its useful.

25 Oct 2007, 6:37 AM
I have not looked at the code but I did read what you ar doing and it seems that this features already exists. it is call children as in:

, children:[ {name:'child1'
, children:[{name:'subchild... etc'}]
} ] }

And if you want them to be rendered you can use: TreeLoader => preloadChildren : Boolean
If set to true, the loader recursively loads "children" attributes when doing the first load on nodes.

25 Oct 2007, 7:13 AM
This was done as a combination of fastest way to generate the data and using our existing parent based structure. Instead of building a complex json that would require server side recursion we simple output a single level json array. We also did not want the children to load initially. We have a site which has happen to grown to over 2000 pages. One option was to load all the nodes upfront but it takes way to long to generate that many. The other option was to use async but we found the response time to be to slow and it added extra load to a server that wasn't needed. Our answer was to perform a single call to server to retrieve the data. Then we simple load the nodes as required. This allowed us to maintain our parent structure but also keep the server and client side loads lite.

Thanks for the suggestion.

25 Oct 2007, 9:19 AM
I know you already have it done but another way to think about it is if you have a static list you can use a script/cronjob that generates cache files somewhere for your async requests that way it doesn't have to hit a db or do a file recursion every time.

Sometimes the fastest way is a lookup table methodology. It is sometimes overlooked when the data is not changed very often.

Either way it is always good to have more ux additions.


25 Oct 2007, 11:03 AM
I actually do cache my list on my server to prevent extra db calls. It was also the issue with the extra calls to the server. On a slower connection the wait for the async node to call the server, respond and then generate nodes can hurt user interactions.

I guess it really is based upon preferences, the focused audenence and application requirements.

Thanks for all your feedback.

1 Apr 2008, 7:55 AM

if i change all above ‘text’ to ‘name’,and i also changed the line

”dataFields: ['id','parentid','text','url'] “ to “dataFields: ['id','parentid','name','url'] ”

the treenode’name do not display !!! why?

Fredric Berling
16 Jun 2008, 6:21 AM
I am in the same situation with a structure built on the childrens knowledge of their parent object and find your solution quite interesting for me. I tested you example but when i have expanded a folder it looses its "folder look" have no "minus" to click. Any ideas?

8 Jan 2010, 4:01 AM
I always found this extension come in very handy. However, it doesn't seem to be working in Ext 3.1 anymore. Does anyone have a solution?