Controller.html 20 KB

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