Upgrade to ExtJS 3.3.1 - Released 11/30/2010
[extjs.git] / docs / source / TreeLoader.html
1 <html>
2 <head>
3   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />    
4   <title>The source code</title>
5     <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
6     <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
7 </head>
8 <body  onload="prettyPrint();">
9     <pre class="prettyprint lang-js">/*!
10  * Ext JS Library 3.3.1
11  * Copyright(c) 2006-2010 Sencha Inc.
12  * licensing@sencha.com
13  * http://www.sencha.com/license
14  */
15 <div id="cls-Ext.tree.TreeLoader"></div>/**
16  * @class Ext.tree.TreeLoader
17  * @extends Ext.util.Observable
18  * A TreeLoader provides for lazy loading of an {@link Ext.tree.TreeNode}'s child
19  * nodes from a specified URL. The response must be a JavaScript Array definition
20  * whose elements are node definition objects. e.g.:
21  * <pre><code>
22     [{
23         id: 1,
24         text: 'A leaf Node',
25         leaf: true
26     },{
27         id: 2,
28         text: 'A folder Node',
29         children: [{
30             id: 3,
31             text: 'A child Node',
32             leaf: true
33         }]
34    }]
35 </code></pre>
36  * <br><br>
37  * A server request is sent, and child nodes are loaded only when a node is expanded.
38  * The loading node's id is passed to the server under the parameter name "node" to
39  * enable the server to produce the correct child nodes.
40  * <br><br>
41  * To pass extra parameters, an event handler may be attached to the "beforeload"
42  * event, and the parameters specified in the TreeLoader's baseParams property:
43  * <pre><code>
44     myTreeLoader.on("beforeload", function(treeLoader, node) {
45         this.baseParams.category = node.attributes.category;
46     }, this);
47 </code></pre>
48  * This would pass an HTTP parameter called "category" to the server containing
49  * the value of the Node's "category" attribute.
50  * @constructor
51  * Creates a new Treeloader.
52  * @param {Object} config A config object containing config properties.
53  */
54 Ext.tree.TreeLoader = function(config){
55     this.baseParams = {};
56     Ext.apply(this, config);
57
58     this.addEvents(
59         <div id="event-Ext.tree.TreeLoader-beforeload"></div>/**
60          * @event beforeload
61          * Fires before a network request is made to retrieve the Json text which specifies a node's children.
62          * @param {Object} This TreeLoader object.
63          * @param {Object} node The {@link Ext.tree.TreeNode} object being loaded.
64          * @param {Object} callback The callback function specified in the {@link #load} call.
65          */
66         "beforeload",
67         <div id="event-Ext.tree.TreeLoader-load"></div>/**
68          * @event load
69          * Fires when the node has been successfuly loaded.
70          * @param {Object} This TreeLoader object.
71          * @param {Object} node The {@link Ext.tree.TreeNode} object being loaded.
72          * @param {Object} response The response object containing the data from the server.
73          */
74         "load",
75         <div id="event-Ext.tree.TreeLoader-loadexception"></div>/**
76          * @event loadexception
77          * Fires if the network request failed.
78          * @param {Object} This TreeLoader object.
79          * @param {Object} node The {@link Ext.tree.TreeNode} object being loaded.
80          * @param {Object} response The response object containing the data from the server.
81          */
82         "loadexception"
83     );
84     Ext.tree.TreeLoader.superclass.constructor.call(this);
85     if(Ext.isString(this.paramOrder)){
86         this.paramOrder = this.paramOrder.split(/[\s,|]/);
87     }
88 };
89
90 Ext.extend(Ext.tree.TreeLoader, Ext.util.Observable, {
91     <div id="cfg-Ext.tree.TreeLoader-dataUrl"></div>/**
92     * @cfg {String} dataUrl The URL from which to request a Json string which
93     * specifies an array of node definition objects representing the child nodes
94     * to be loaded.
95     */
96     <div id="cfg-Ext.tree.TreeLoader-requestMethod"></div>/**
97      * @cfg {String} requestMethod The HTTP request method for loading data (defaults to the value of {@link Ext.Ajax#method}).
98      */
99     <div id="cfg-Ext.tree.TreeLoader-url"></div>/**
100      * @cfg {String} url Equivalent to {@link #dataUrl}.
101      */
102     <div id="cfg-Ext.tree.TreeLoader-preloadChildren"></div>/**
103      * @cfg {Boolean} preloadChildren If set to true, the loader recursively loads "children" attributes when doing the first load on nodes.
104      */
105     <div id="cfg-Ext.tree.TreeLoader-baseParams"></div>/**
106     * @cfg {Object} baseParams (optional) An object containing properties which
107     * specify HTTP parameters to be passed to each request for child nodes.
108     */
109     <div id="cfg-Ext.tree.TreeLoader-baseAttrs"></div>/**
110     * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
111     * created by this loader. If the attributes sent by the server have an attribute in this object,
112     * they take priority.
113     */
114     <div id="cfg-Ext.tree.TreeLoader-uiProviders"></div>/**
115     * @cfg {Object} uiProviders (optional) An object containing properties which
116     * specify custom {@link Ext.tree.TreeNodeUI} implementations. If the optional
117     * <i>uiProvider</i> attribute of a returned child node is a string rather
118     * than a reference to a TreeNodeUI implementation, then that string value
119     * is used as a property name in the uiProviders object.
120     */
121     uiProviders : {},
122
123     <div id="cfg-Ext.tree.TreeLoader-clearOnLoad"></div>/**
124     * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
125     * child nodes before loading.
126     */
127     clearOnLoad : true,
128
129     <div id="cfg-Ext.tree.TreeLoader-paramOrder"></div>/**
130      * @cfg {Array/String} paramOrder Defaults to <tt>undefined</tt>. Only used when using directFn.
131      * Specifies the params in the order in which they must be passed to the server-side Direct method
132      * as either (1) an Array of String values, or (2) a String of params delimited by either whitespace,
133      * comma, or pipe. For example,
134      * any of the following would be acceptable:<pre><code>
135 nodeParameter: 'node',
136 paramOrder: ['param1','param2','param3']
137 paramOrder: 'node param1 param2 param3'
138 paramOrder: 'param1,node,param2,param3'
139 paramOrder: 'param1|param2|param|node'
140      </code></pre>
141      */
142     paramOrder: undefined,
143
144     <div id="cfg-Ext.tree.TreeLoader-paramsAsHash"></div>/**
145      * @cfg {Boolean} paramsAsHash Only used when using directFn.
146      * Send parameters as a collection of named arguments (defaults to <tt>false</tt>). Providing a
147      * <tt>{@link #paramOrder}</tt> nullifies this configuration.
148      */
149     paramsAsHash: false,
150
151     <div id="cfg-Ext.tree.TreeLoader-nodeParameter"></div>/**
152      * @cfg {String} nodeParameter The name of the parameter sent to the server which contains
153      * the identifier of the node. Defaults to <tt>'node'</tt>.
154      */
155     nodeParameter: 'node',
156
157     <div id="cfg-Ext.tree.TreeLoader-directFn"></div>/**
158      * @cfg {Function} directFn
159      * Function to call when executing a request.
160      */
161     directFn : undefined,
162
163     <div id="method-Ext.tree.TreeLoader-load"></div>/**
164      * Load an {@link Ext.tree.TreeNode} from the URL specified in the constructor.
165      * This is called automatically when a node is expanded, but may be used to reload
166      * a node (or append new children if the {@link #clearOnLoad} option is false.)
167      * @param {Ext.tree.TreeNode} node
168      * @param {Function} callback Function to call after the node has been loaded. The
169      * function is passed the TreeNode which was requested to be loaded.
170      * @param {Object} scope The scope (<code>this</code> reference) in which the callback is executed.
171      * defaults to the loaded TreeNode.
172      */
173     load : function(node, callback, scope){
174         if(this.clearOnLoad){
175             while(node.firstChild){
176                 node.removeChild(node.firstChild);
177             }
178         }
179         if(this.doPreload(node)){ // preloaded json children
180             this.runCallback(callback, scope || node, [node]);
181         }else if(this.directFn || this.dataUrl || this.url){
182             this.requestData(node, callback, scope || node);
183         }
184     },
185
186     doPreload : function(node){
187         if(node.attributes.children){
188             if(node.childNodes.length < 1){ // preloaded?
189                 var cs = node.attributes.children;
190                 node.beginUpdate();
191                 for(var i = 0, len = cs.length; i < len; i++){
192                     var cn = node.appendChild(this.createNode(cs[i]));
193                     if(this.preloadChildren){
194                         this.doPreload(cn);
195                     }
196                 }
197                 node.endUpdate();
198             }
199             return true;
200         }
201         return false;
202     },
203
204     getParams: function(node){
205         var bp = Ext.apply({}, this.baseParams),
206             np = this.nodeParameter,
207             po = this.paramOrder;
208
209         np && (bp[ np ] = node.id);
210
211         if(this.directFn){
212             var buf = [node.id];
213             if(po){
214                 // reset 'buf' if the nodeParameter was included in paramOrder
215                 if(np && po.indexOf(np) > -1){
216                     buf = [];
217                 }
218
219                 for(var i = 0, len = po.length; i < len; i++){
220                     buf.push(bp[ po[i] ]);
221                 }
222             }else if(this.paramsAsHash){
223                 buf = [bp];
224             }
225             return buf;
226         }else{
227             return bp;
228         }
229     },
230
231     requestData : function(node, callback, scope){
232         if(this.fireEvent("beforeload", this, node, callback) !== false){
233             if(this.directFn){
234                 var args = this.getParams(node);
235                 args.push(this.processDirectResponse.createDelegate(this, [{callback: callback, node: node, scope: scope}], true));
236                 this.directFn.apply(window, args);
237             }else{
238                 this.transId = Ext.Ajax.request({
239                     method:this.requestMethod,
240                     url: this.dataUrl||this.url,
241                     success: this.handleResponse,
242                     failure: this.handleFailure,
243                     scope: this,
244                     argument: {callback: callback, node: node, scope: scope},
245                     params: this.getParams(node)
246                 });
247             }
248         }else{
249             // if the load is cancelled, make sure we notify
250             // the node that we are done
251             this.runCallback(callback, scope || node, []);
252         }
253     },
254
255     processDirectResponse: function(result, response, args){
256         if(response.status){
257             this.handleResponse({
258                 responseData: Ext.isArray(result) ? result : null,
259                 responseText: result,
260                 argument: args
261             });
262         }else{
263             this.handleFailure({
264                 argument: args
265             });
266         }
267     },
268
269     // private
270     runCallback: function(cb, scope, args){
271         if(Ext.isFunction(cb)){
272             cb.apply(scope, args);
273         }
274     },
275
276     isLoading : function(){
277         return !!this.transId;
278     },
279
280     abort : function(){
281         if(this.isLoading()){
282             Ext.Ajax.abort(this.transId);
283         }
284     },
285
286     <div id="method-Ext.tree.TreeLoader-createNode"></div>/**
287     * <p>Override this function for custom TreeNode node implementation, or to
288     * modify the attributes at creation time.</p>
289     * Example:<pre><code>
290 new Ext.tree.TreePanel({
291     ...
292     loader: new Ext.tree.TreeLoader({
293         url: 'dataUrl',
294         createNode: function(attr) {
295 //          Allow consolidation consignments to have
296 //          consignments dropped into them.
297             if (attr.isConsolidation) {
298                 attr.iconCls = 'x-consol',
299                 attr.allowDrop = true;
300             }
301             return Ext.tree.TreeLoader.prototype.createNode.call(this, attr);
302         }
303     }),
304     ...
305 });
306 </code></pre>
307     * @param attr {Object} The attributes from which to create the new node.
308     */
309     createNode : function(attr){
310         // apply baseAttrs, nice idea Corey!
311         if(this.baseAttrs){
312             Ext.applyIf(attr, this.baseAttrs);
313         }
314         if(this.applyLoader !== false && !attr.loader){
315             attr.loader = this;
316         }
317         if(Ext.isString(attr.uiProvider)){
318            attr.uiProvider = this.uiProviders[attr.uiProvider] || eval(attr.uiProvider);
319         }
320         if(attr.nodeType){
321             return new Ext.tree.TreePanel.nodeTypes[attr.nodeType](attr);
322         }else{
323             return attr.leaf ?
324                         new Ext.tree.TreeNode(attr) :
325                         new Ext.tree.AsyncTreeNode(attr);
326         }
327     },
328
329     processResponse : function(response, node, callback, scope){
330         var json = response.responseText;
331         try {
332             var o = response.responseData || Ext.decode(json);
333             node.beginUpdate();
334             for(var i = 0, len = o.length; i < len; i++){
335                 var n = this.createNode(o[i]);
336                 if(n){
337                     node.appendChild(n);
338                 }
339             }
340             node.endUpdate();
341             this.runCallback(callback, scope || node, [node]);
342         }catch(e){
343             this.handleFailure(response);
344         }
345     },
346
347     handleResponse : function(response){
348         this.transId = false;
349         var a = response.argument;
350         this.processResponse(response, a.node, a.callback, a.scope);
351         this.fireEvent("load", this, a.node, response);
352     },
353
354     handleFailure : function(response){
355         this.transId = false;
356         var a = response.argument;
357         this.fireEvent("loadexception", this, a.node, response);
358         this.runCallback(a.callback, a.scope || a.node, [a.node]);
359     },
360
361     destroy : function(){
362         this.abort();
363         this.purgeListeners();
364     }
365 });</pre>    
366 </body>
367 </html>