Upgrade to ExtJS 4.0.0 - Released 04/26/2011
[extjs.git] / docs / source / Controller.html
1 <!DOCTYPE html><html><head><title>Sencha Documentation Project</title><link rel="stylesheet" href="../reset.css" type="text/css"><link rel="stylesheet" href="../prettify.css" type="text/css"><link rel="stylesheet" href="../prettify_sa.css" type="text/css"><script type="text/javascript" src="../prettify.js"></script></head><body onload="prettyPrint()"><pre class="prettyprint"><pre><span id='Ext-app.Controller-method-constructor'><span id='Ext-app.Controller'>/**
2 </span></span> * @class Ext.app.Controller
3  * @constructor
4  * 
5  * Controllers are the glue that binds an application together. All they really do is listen for events (usually from
6  * views) and take some action. Here's how we might create a Controller to manage Users:
7  * 
8  *     Ext.define('MyApp.controller.Users', {
9  *         extend: 'Ext.app.Controller',
10  * 
11  *         init: function() {
12  *             console.log('Initialized Users! This happens before the Application launch function is called');
13  *         }
14  *     });
15  * 
16  * The init function is a special method that is called when your application boots. It is called before the 
17  * {@link Ext.app.Application Application}'s launch function is executed so gives a hook point to run any code before
18  * your Viewport is created.
19  * 
20  * The init function is a great place to set up how your controller interacts with the view, and is usually used in 
21  * conjunction with another Controller function - {@link Ext.app.Controller#control control}. The control function 
22  * makes it easy to listen to events on your view classes and take some action with a handler function. Let's update
23  * our Users controller to tell us when the panel is rendered:
24  * 
25  *     Ext.define('MyApp.controller.Users', {
26  *         extend: 'Ext.app.Controller',
27  * 
28  *         init: function() {
29  *             this.control({
30  *                 'viewport &gt; panel': {
31  *                     render: this.onPanelRendered
32  *                 }
33  *             });
34  *         },
35  * 
36  *         onPanelRendered: function() {
37  *             console.log('The panel was rendered');
38  *         }
39  *     });
40  * 
41  * We've updated the init function to use this.control to set up listeners on views in our application. The control
42  * function uses the new ComponentQuery engine to quickly and easily get references to components on the page. If you
43  * are not familiar with ComponentQuery yet, be sure to check out THIS GUIDE for a full explanation. In brief though,
44  * it allows us to pass a CSS-like selector that will find every matching component on the page.
45  * 
46  * In our init function above we supplied 'viewport &gt; panel', which translates to &quot;find me every Panel that is a direct
47  * child of a Viewport&quot;. We then supplied an object that maps event names (just 'render' in this case) to handler 
48  * functions. The overall effect is that whenever any component that matches our selector fires a 'render' event, our 
49  * onPanelRendered function is called.
50  * 
51  * &lt;u&gt;Using refs&lt;/u&gt;
52  * 
53  * One of the most useful parts of Controllers is the new ref system. These use the new {@link Ext.ComponentQuery} to
54  * make it really easy to get references to Views on your page. Let's look at an example of this now:
55  * 
56  * Ext.define('MyApp.controller.Users', {
57      extend: 'Ext.app.Controller',
58
59      refs: [
60          {
61              ref: 'list',
62              selector: 'grid'
63          }
64      ],
65
66      init: function() {
67          this.control({
68              'button': {
69                  click: this.refreshGrid
70              }
71          });
72      },
73
74      refreshGrid: function() {
75          this.getList().store.load();
76      }
77  });
78  * 
79  * This example assumes the existence of a {@link Ext.grid.Panel Grid} on the page, which contains a single button to 
80  * refresh the Grid when clicked. In our refs array, we set up a reference to the grid. There are two parts to this - 
81  * the 'selector', which is a {@link Ext.ComponentQuery ComponentQuery} selector which finds any grid on the page and
82  * assigns it to the reference 'list'.
83  * 
84  * By giving the reference a name, we get a number of things for free. The first is the getList function that we use in
85  * the refreshGrid method above. This is generated automatically by the Controller based on the name of our ref, which 
86  * was capitalized and prepended with get to go from 'list' to 'getList'.
87  * 
88  * The way this works is that the first time getList is called by your code, the ComponentQuery selector is run and the
89  * first component that matches the selector ('grid' in this case) will be returned. All future calls to getList will 
90  * use a cached reference to that grid. Usually it is advised to use a specific ComponentQuery selector that will only
91  * match a single View in your application (in the case above our selector will match any grid on the page).
92  * 
93  * Bringing it all together, our init function is called when the application boots, at which time we call this.control
94  * to listen to any click on a {@link Ext.button.Button button} and call our refreshGrid function (again, this will 
95  * match any button on the page so we advise a more specific selector than just 'button', but have left it this way for
96  * simplicity). When the button is clicked we use out getList function to refresh the grid.
97  * 
98  * You can create any number of refs and control any number of components this way, simply adding more functions to 
99  * your Controller as you go. For an example of real-world usage of Controllers see the Feed Viewer example in the 
100  * examples/app/feed-viewer folder in the SDK download.
101  * 
102  * &lt;u&gt;Generated getter methods&lt;/u&gt;
103  * 
104  * Refs aren't the only thing that generate convenient getter methods. Controllers often have to deal with Models and 
105  * Stores so the framework offers a couple of easy ways to get access to those too. Let's look at another example:
106  * 
107  * Ext.define('MyApp.controller.Users', {
108      extend: 'Ext.app.Controller',
109
110      models: ['User'],
111      stores: ['AllUsers', 'AdminUsers'],
112
113      init: function() {
114          var User = this.getUserModel(),
115              allUsers = this.getAllUsersStore();
116
117          var ed = new User({name: 'Ed'});
118          allUsers.add(ed);
119      }
120  });
121  * 
122  * By specifying Models and Stores that the Controller cares about, it again dynamically loads them from the appropriate
123  * locations (app/model/User.js, app/store/AllUsers.js and app/store/AdminUsers.js in this case) and creates getter 
124  * functions for them all. The example above will create a new User model instance and add it to the AllUsers Store.
125  * Of course, you could do anything in this function but in this case we just did something simple to demonstrate the 
126  * functionality.
127  * 
128  * &lt;u&gt;Further Reading&lt;/u&gt;
129  * 
130  * For more information about writing Ext JS 4 applications, please see the &lt;a href=&quot;../guide/application_architecture&quot;&gt;
131  * application architecture guide&lt;/a&gt;. Also see the {@link Ext.app.Application} documentation.
132  * 
133  * @markdown
134  * @docauthor Ed Spencer
135  */  
136 Ext.define('Ext.app.Controller', {
137 <span id='Ext-app.Controller-cfg-id'>    /**
138 </span>     * @cfg {Object} id The id of this controller. You can use this id when dispatching.
139      */
140
141     mixins: {
142         observable: 'Ext.util.Observable'
143     },
144
145     onClassExtended: function(cls, data) {
146         var className = Ext.getClassName(cls),
147             match = className.match(/^(.*)\.controller\./);
148
149         if (match !== null) {
150             var namespace = Ext.Loader.getPrefix(className) || match[1],
151                 onBeforeClassCreated = data.onBeforeClassCreated,
152                 requires = [],
153                 modules = ['model', 'view', 'store'],
154                 prefix;
155
156             data.onBeforeClassCreated = function(cls, data) {
157                 var i, ln, module,
158                     items, j, subLn, item;
159
160                 for (i = 0,ln = modules.length; i &lt; ln; i++) {
161                     module = modules[i];
162
163                     items = Ext.Array.from(data[module + 's']);
164
165                     for (j = 0,subLn = items.length; j &lt; subLn; j++) {
166                         item = items[j];
167
168                         prefix = Ext.Loader.getPrefix(item);
169
170                         if (prefix === '' || prefix === item) {
171                             requires.push(namespace + '.' + module + '.' + item);
172                         }
173                         else {
174                             requires.push(item);
175                         }
176                     }
177                 }
178
179                 Ext.require(requires, Ext.Function.pass(onBeforeClassCreated, arguments, this));
180             };
181         }
182     },
183
184     constructor: function(config) {
185         this.mixins.observable.constructor.call(this, config);
186
187         Ext.apply(this, config || {});
188
189         this.createGetters('model', this.models);
190         this.createGetters('store', this.stores);
191         this.createGetters('view', this.views);
192
193         if (this.refs) {
194             this.ref(this.refs);
195         }
196     },
197
198     // Template method
199     init: function(application) {},
200     // Template method
201     onLaunch: function(application) {},
202
203     createGetters: function(type, refs) {
204         type = Ext.String.capitalize(type);
205         Ext.Array.each(refs, function(ref) {
206             var fn = 'get',
207                 parts = ref.split('.');
208
209             // Handle namespaced class names. E.g. feed.Add becomes getFeedAddView etc.
210             Ext.Array.each(parts, function(part) {
211                 fn += Ext.String.capitalize(part);
212             });
213             fn += type;
214
215             if (!this[fn]) {
216                 this[fn] = Ext.Function.pass(this['get' + type], [ref], this);
217             }
218             // Execute it right away
219             this[fn](ref);
220         },
221         this);
222     },
223
224     ref: function(refs) {
225         var me = this;
226         refs = Ext.Array.from(refs);
227         Ext.Array.each(refs, function(info) {
228             var ref = info.ref,
229                 fn = 'get' + Ext.String.capitalize(ref);
230             if (!me[fn]) {
231                 me[fn] = Ext.Function.pass(me.getRef, [ref, info], me);
232             }
233         });
234     },
235
236     getRef: function(ref, info, config) {
237         this.refCache = this.refCache || {};
238         info = info || {};
239         config = config || {};
240
241         Ext.apply(info, config);
242
243         if (info.forceCreate) {
244             return Ext.ComponentManager.create(info, 'component');
245         }
246
247         var me = this,
248             selector = info.selector,
249             cached = me.refCache[ref];
250
251         if (!cached) {
252             me.refCache[ref] = cached = Ext.ComponentQuery.query(info.selector)[0];
253             if (!cached &amp;&amp; info.autoCreate) {
254                 me.refCache[ref] = cached = Ext.ComponentManager.create(info, 'component');
255             }
256             if (cached) {
257                 cached.on('beforedestroy', function() {
258                     me.refCache[ref] = null;
259                 });
260             }
261         }
262
263         return cached;
264     },
265
266     control: function(selectors, listeners) {
267         this.application.control(selectors, listeners, this);
268     },
269
270     getController: function(name) {
271         return this.application.getController(name);
272     },
273
274     getStore: function(name) {
275         return this.application.getStore(name);
276     },
277
278     getModel: function(model) {
279         return this.application.getModel(model);
280     },
281
282     getView: function(view) {
283         return this.application.getView(view);
284     }
285 });
286 </pre></pre></body></html>