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