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