Upgrade to ExtJS 4.0.7 - Released 10/19/2011
[extjs.git] / docs / source / Controller.html
1 <!DOCTYPE html>
2 <html>
3 <head>
4   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5   <title>The source code</title>
6   <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
7   <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
8   <style type="text/css">
9     .highlight { display: block; background-color: #ddd; }
10   </style>
11   <script type="text/javascript">
12     function highlight() {
13       document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
14     }
15   </script>
16 </head>
17 <body onload="prettyPrint(); highlight();">
18   <pre class="prettyprint lang-js"><span id='Ext-app-Controller'>/**
19 </span> * @class Ext.app.Controller
20  *
21  * Controllers are the glue that binds an application together. All they really do is listen for events (usually from
22  * views) and take some action. Here's how we might create a Controller to manage Users:
23  *
24  *     Ext.define('MyApp.controller.Users', {
25  *         extend: 'Ext.app.Controller',
26  *
27  *         init: function() {
28  *             console.log('Initialized Users! This happens before the Application launch function is called');
29  *         }
30  *     });
31  *
32  * The init function is a special method that is called when your application boots. It is called before the
33  * {@link Ext.app.Application Application}'s launch function is executed so gives a hook point to run any code before
34  * your Viewport is created.
35  *
36  * The init function is a great place to set up how your controller interacts with the view, and is usually used in
37  * conjunction with another Controller function - {@link Ext.app.Controller#control control}. The control function
38  * makes it easy to listen to events on your view classes and take some action with a handler function. Let's update
39  * our Users controller to tell us when the panel is rendered:
40  *
41  *     Ext.define('MyApp.controller.Users', {
42  *         extend: 'Ext.app.Controller',
43  *
44  *         init: function() {
45  *             this.control({
46  *                 'viewport &gt; panel': {
47  *                     render: this.onPanelRendered
48  *                 }
49  *             });
50  *         },
51  *
52  *         onPanelRendered: function() {
53  *             console.log('The panel was rendered');
54  *         }
55  *     });
56  *
57  * We've updated the init function to use this.control to set up listeners on views in our application. The control
58  * function uses the new ComponentQuery engine to quickly and easily get references to components on the page. If you
59  * are not familiar with ComponentQuery yet, be sure to check out the {@link Ext.ComponentQuery documentation}. In brief though,
60  * it allows us to pass a CSS-like selector that will find every matching component on the page.
61  *
62  * In our init function above we supplied 'viewport &gt; panel', which translates to &quot;find me every Panel that is a direct
63  * child of a Viewport&quot;. We then supplied an object that maps event names (just 'render' in this case) to handler
64  * functions. The overall effect is that whenever any component that matches our selector fires a 'render' event, our
65  * onPanelRendered function is called.
66  *
67  * &lt;u&gt;Using refs&lt;/u&gt;
68  *
69  * One of the most useful parts of Controllers is the new ref system. These use the new {@link Ext.ComponentQuery} to
70  * make it really easy to get references to Views on your page. Let's look at an example of this now:
71  *
72  *     Ext.define('MyApp.controller.Users', {
73  *         extend: 'Ext.app.Controller',
74  *
75  *         refs: [
76  *             {
77  *                 ref: 'list',
78  *                 selector: 'grid'
79  *             }
80  *         ],
81  *
82  *         init: function() {
83  *             this.control({
84  *                 'button': {
85  *                     click: this.refreshGrid
86  *                 }
87  *             });
88  *         },
89  *
90  *         refreshGrid: function() {
91  *             this.getList().store.load();
92  *         }
93  *     });
94  *
95  * This example assumes the existence of a {@link Ext.grid.Panel Grid} on the page, which contains a single button to
96  * refresh the Grid when clicked. In our refs array, we set up a reference to the grid. There are two parts to this -
97  * the 'selector', which is a {@link Ext.ComponentQuery ComponentQuery} selector which finds any grid on the page and
98  * assigns it to the reference 'list'.
99  *
100  * By giving the reference a name, we get a number of things for free. The first is the getList function that we use in
101  * the refreshGrid method above. This is generated automatically by the Controller based on the name of our ref, which
102  * was capitalized and prepended with get to go from 'list' to 'getList'.
103  *
104  * The way this works is that the first time getList is called by your code, the ComponentQuery selector is run and the
105  * first component that matches the selector ('grid' in this case) will be returned. All future calls to getList will
106  * use a cached reference to that grid. Usually it is advised to use a specific ComponentQuery selector that will only
107  * match a single View in your application (in the case above our selector will match any grid on the page).
108  *
109  * Bringing it all together, our init function is called when the application boots, at which time we call this.control
110  * to listen to any click on a {@link Ext.button.Button button} and call our refreshGrid function (again, this will
111  * match any button on the page so we advise a more specific selector than just 'button', but have left it this way for
112  * simplicity). When the button is clicked we use out getList function to refresh the grid.
113  *
114  * You can create any number of refs and control any number of components this way, simply adding more functions to
115  * your Controller as you go. For an example of real-world usage of Controllers see the Feed Viewer example in the
116  * examples/app/feed-viewer folder in the SDK download.
117  *
118  * &lt;u&gt;Generated getter methods&lt;/u&gt;
119  *
120  * Refs aren't the only thing that generate convenient getter methods. Controllers often have to deal with Models and
121  * Stores so the framework offers a couple of easy ways to get access to those too. Let's look at another example:
122  *
123  *     Ext.define('MyApp.controller.Users', {
124  *         extend: 'Ext.app.Controller',
125  *
126  *         models: ['User'],
127  *         stores: ['AllUsers', 'AdminUsers'],
128  *
129  *         init: function() {
130  *             var User = this.getUserModel(),
131  *                 allUsers = this.getAllUsersStore();
132  *
133  *             var ed = new User({name: 'Ed'});
134  *             allUsers.add(ed);
135  *         }
136  *     });
137  *
138  * By specifying Models and Stores that the Controller cares about, it again dynamically loads them from the appropriate
139  * locations (app/model/User.js, app/store/AllUsers.js and app/store/AdminUsers.js in this case) and creates getter
140  * functions for them all. The example above will create a new User model instance and add it to the AllUsers Store.
141  * Of course, you could do anything in this function but in this case we just did something simple to demonstrate the
142  * functionality.
143  *
144  * &lt;u&gt;Further Reading&lt;/u&gt;
145  *
146  * For more information about writing Ext JS 4 applications, please see the
147  * [application architecture guide](#/guide/application_architecture). Also see the {@link Ext.app.Application} documentation.
148  *
149  * @docauthor Ed Spencer
150  */
151 Ext.define('Ext.app.Controller', {
152
153     mixins: {
154         observable: 'Ext.util.Observable'
155     },
156
157 <span id='Ext-app-Controller-cfg-id'>    /**
158 </span>     * @cfg {String} id The id of this controller. You can use this id when dispatching.
159      */
160     
161 <span id='Ext-app-Controller-cfg-models'>    /**
162 </span>     * @cfg {String[]} models
163      * Array of models to require from AppName.model namespace. For example:
164      * 
165      *     Ext.define(&quot;MyApp.controller.Foo&quot;, {
166      *         extend: &quot;Ext.app.Controller&quot;,
167      *         models: ['User', 'Vehicle']
168      *     });
169      * 
170      * This is equivalent of:
171      * 
172      *     Ext.define(&quot;MyApp.controller.Foo&quot;, {
173      *         extend: &quot;Ext.app.Controller&quot;,
174      *         requires: ['MyApp.model.User', 'MyApp.model.Vehicle']
175      *     });
176      * 
177      */
178
179 <span id='Ext-app-Controller-cfg-views'>    /**
180 </span>     * @cfg {String[]} views
181      * Array of views to require from AppName.view namespace. For example:
182      * 
183      *     Ext.define(&quot;MyApp.controller.Foo&quot;, {
184      *         extend: &quot;Ext.app.Controller&quot;,
185      *         views: ['List', 'Detail']
186      *     });
187      * 
188      * This is equivalent of:
189      * 
190      *     Ext.define(&quot;MyApp.controller.Foo&quot;, {
191      *         extend: &quot;Ext.app.Controller&quot;,
192      *         requires: ['MyApp.view.List', 'MyApp.view.Detail']
193      *     });
194      * 
195      */
196
197 <span id='Ext-app-Controller-cfg-stores'>    /**
198 </span>     * @cfg {String[]} stores
199      * Array of stores to require from AppName.store namespace. For example:
200      * 
201      *     Ext.define(&quot;MyApp.controller.Foo&quot;, {
202      *         extend: &quot;Ext.app.Controller&quot;,
203      *         stores: ['Users', 'Vehicles']
204      *     });
205      * 
206      * This is equivalent of:
207      * 
208      *     Ext.define(&quot;MyApp.controller.Foo&quot;, {
209      *         extend: &quot;Ext.app.Controller&quot;,
210      *         requires: ['MyApp.store.Users', 'MyApp.store.Vehicles']
211      *     });
212      * 
213      */
214
215     onClassExtended: function(cls, data) {
216         var className = Ext.getClassName(cls),
217             match = className.match(/^(.*)\.controller\./);
218
219         if (match !== null) {
220             var namespace = Ext.Loader.getPrefix(className) || match[1],
221                 onBeforeClassCreated = data.onBeforeClassCreated,
222                 requires = [],
223                 modules = ['model', 'view', 'store'],
224                 prefix;
225
226             data.onBeforeClassCreated = function(cls, data) {
227                 var i, ln, module,
228                     items, j, subLn, item;
229
230                 for (i = 0,ln = modules.length; i &lt; ln; i++) {
231                     module = modules[i];
232
233                     items = Ext.Array.from(data[module + 's']);
234
235                     for (j = 0,subLn = items.length; j &lt; subLn; j++) {
236                         item = items[j];
237
238                         prefix = Ext.Loader.getPrefix(item);
239
240                         if (prefix === '' || prefix === item) {
241                             requires.push(namespace + '.' + module + '.' + item);
242                         }
243                         else {
244                             requires.push(item);
245                         }
246                     }
247                 }
248
249                 Ext.require(requires, Ext.Function.pass(onBeforeClassCreated, arguments, this));
250             };
251         }
252     },
253
254 <span id='Ext-app-Controller-method-constructor'>    /**
255 </span>     * Creates new Controller.
256      * @param {Object} config (optional) Config object.
257      */
258     constructor: function(config) {
259         this.mixins.observable.constructor.call(this, config);
260
261         Ext.apply(this, config || {});
262
263         this.createGetters('model', this.models);
264         this.createGetters('store', this.stores);
265         this.createGetters('view', this.views);
266
267         if (this.refs) {
268             this.ref(this.refs);
269         }
270     },
271
272 <span id='Ext-app-Controller-method-init'>    /**
273 </span>     * A template method that is called when your application boots. It is called before the
274      * {@link Ext.app.Application Application}'s launch function is executed so gives a hook point to run any code before
275      * your Viewport is created.
276      * 
277      * @param {Ext.app.Application} application
278      * @template
279      */
280     init: function(application) {},
281
282 <span id='Ext-app-Controller-method-onLaunch'>    /**
283 </span>     * A template method like {@link #init}, but called after the viewport is created.
284      * This is called after the {@link Ext.app.Application#launch launch} method of Application is executed.
285      * 
286      * @param {Ext.app.Application} application
287      * @template
288      */
289     onLaunch: function(application) {},
290
291     createGetters: function(type, refs) {
292         type = Ext.String.capitalize(type);
293         Ext.Array.each(refs, function(ref) {
294             var fn = 'get',
295                 parts = ref.split('.');
296
297             // Handle namespaced class names. E.g. feed.Add becomes getFeedAddView etc.
298             Ext.Array.each(parts, function(part) {
299                 fn += Ext.String.capitalize(part);
300             });
301             fn += type;
302
303             if (!this[fn]) {
304                 this[fn] = Ext.Function.pass(this['get' + type], [ref], this);
305             }
306             // Execute it right away
307             this[fn](ref);
308         },
309         this);
310     },
311
312     ref: function(refs) {
313         var me = this;
314         refs = Ext.Array.from(refs);
315         Ext.Array.each(refs, function(info) {
316             var ref = info.ref,
317                 fn = 'get' + Ext.String.capitalize(ref);
318             if (!me[fn]) {
319                 me[fn] = Ext.Function.pass(me.getRef, [ref, info], me);
320             }
321         });
322     },
323
324     getRef: function(ref, info, config) {
325         this.refCache = this.refCache || {};
326         info = info || {};
327         config = config || {};
328
329         Ext.apply(info, config);
330
331         if (info.forceCreate) {
332             return Ext.ComponentManager.create(info, 'component');
333         }
334
335         var me = this,
336             selector = info.selector,
337             cached = me.refCache[ref];
338
339         if (!cached) {
340             me.refCache[ref] = cached = Ext.ComponentQuery.query(info.selector)[0];
341             if (!cached &amp;&amp; info.autoCreate) {
342                 me.refCache[ref] = cached = Ext.ComponentManager.create(info, 'component');
343             }
344             if (cached) {
345                 cached.on('beforedestroy', function() {
346                     me.refCache[ref] = null;
347                 });
348             }
349         }
350
351         return cached;
352     },
353
354 <span id='Ext-app-Controller-method-control'>    /**
355 </span>     * Adds listeners to components selected via {@link Ext.ComponentQuery}. Accepts an
356      * object containing component paths mapped to a hash of listener functions.
357      *
358      * In the following example the `updateUser` function is mapped to to the `click`
359      * event on a button component, which is a child of the `useredit` component.
360      *
361      *     Ext.define('AM.controller.Users', {
362      *         init: function() {
363      *             this.control({
364      *                 'useredit button[action=save]': {
365      *                     click: this.updateUser
366      *                 }
367      *             });
368      *         },
369      *
370      *         updateUser: function(button) {
371      *             console.log('clicked the Save button');
372      *         }
373      *     });
374      *
375      * See {@link Ext.ComponentQuery} for more information on component selectors.
376      *
377      * @param {String/Object} selectors If a String, the second argument is used as the
378      * listeners, otherwise an object of selectors -&gt; listeners is assumed
379      * @param {Object} listeners
380      */
381     control: function(selectors, listeners) {
382         this.application.control(selectors, listeners, this);
383     },
384
385 <span id='Ext-app-Controller-method-getController'>    /**
386 </span>     * Returns instance of a {@link Ext.app.Controller controller} with the given name.
387      * When controller doesn't exist yet, it's created.
388      * @param {String} name
389      * @return {Ext.app.Controller} a controller instance.
390      */
391     getController: function(name) {
392         return this.application.getController(name);
393     },
394
395 <span id='Ext-app-Controller-method-getStore'>    /**
396 </span>     * Returns instance of a {@link Ext.data.Store Store} with the given name.
397      * When store doesn't exist yet, it's created.
398      * @param {String} name
399      * @return {Ext.data.Store} a store instance.
400      */
401     getStore: function(name) {
402         return this.application.getStore(name);
403     },
404
405 <span id='Ext-app-Controller-method-getModel'>    /**
406 </span>     * Returns a {@link Ext.data.Model Model} class with the given name.
407      * A shorthand for using {@link Ext.ModelManager#getModel}.
408      * @param {String} name
409      * @return {Ext.data.Model} a model class.
410      */
411     getModel: function(model) {
412         return this.application.getModel(model);
413     },
414
415 <span id='Ext-app-Controller-method-getView'>    /**
416 </span>     * Returns a View class with the given name.  To create an instance of the view,
417      * you can use it like it's used by Application to create the Viewport:
418      * 
419      *     this.getView('Viewport').create();
420      * 
421      * @param {String} name
422      * @return {Ext.Base} a view class.
423      */
424     getView: function(view) {
425         return this.application.getView(view);
426     }
427 });
428 </pre>
429 </body>
430 </html>