ExtJS: What's the point of requires?

16,448

This is actually not a dumb question at all.

You can look at requires as a way to tell ExtJS:

"When you construct an object of this class, please make sure to dynamically load the required scripts first".

You are right about this line:

requires: ['Test.Utils', 'Test.Utils2'],

not being needed in app.js, reason being is that the application already has:

controllers: ['TheController'],

which is the same as saying you require the js script in which TheController resides (any model/view/controller/store definition also mean that the related scripts are required, ie will be dynamically loaded).

TheController has:

requires: ['Test.model.TheModel', 'Test.Utils'],

which will load these dynamically - this is why the same requires is not needed it app.js;

The reason you get Firebug throwing Test.Utils is undefined is that you give a config (hello) with a reference to an object that is not yet dynamically loaded - there's no Test.Utils in the scope until TheStore is constructed.

Share:
16,448
incutonez
Author by

incutonez

Web developer that enjoys building web applications full of pizzazz. I'm a reformed Ext JS developer that's currently loving Vue.js.

Updated on June 06, 2022

Comments

  • incutonez
    incutonez almost 2 years

    I've been trying to figure out what requires does in Ext JS 4, and I can't seem to come up with a reasonable answer. Let's say I have the following code:

    app.js

    Ext.Loader.setConfig({
      enabled: true
    });
    
    Ext.Loader.setPath('Ext.ux', 'examples/ux');
    
    Ext.application({
      name: 'Test',
      appFolder: 'app',
      controllers: ['TheController'],
      requires: ['Test.Utils', 'Test.Utils2'],  // I don't think this does anything... couldn't find this option for Ext.application
      launch: function() {
        Ext.create('Ext.Viewport', {
          layout: 'border',
          items: [{
            xtype: 'thegrid',
            region: 'center',
            title: 'blah!'
          }]
        });
      }
    });
    

    app/controller/TheController.js

    Ext.define('Test.controller.TheController', {
      extend: 'Ext.app.Controller',
      models: ['TheModel'],
      stores: ['TheStore'],
      views: ['TheGrid'],
      init: function() {
      }
    });
    

    app/view/TheGrid.js

    Ext.define('Test.view.TheGrid', {
      extend: 'Ext.grid.Panel',
      alias: 'widget.thegrid',
      requires: ['Test.store.TheStore'],
      store: 'TheStore',
      columns: [
        {header: 'Name', dataIndex: 'name'},
        {header: 'Phone', dataIndex: 'phone'},
        {header: 'Hello', dataIndex: 'hello'}
      ]
    });
    

    app/store/TheStore.js

    Ext.define('Test.store.TheStore', {
      extend: 'Ext.data.Store',
      requires: ['Test.model.TheModel', 'Test.Utils'],
      model: 'Test.model.TheModel',
      data: [
        {name: 'keanu reeves', phone: '1800matrices', hello: Test.Utils.getText()},
        {name: 'james earl jones', phone: '1800starwar', hello: 'nothing here'},
        {name: 'barack obama', phone: '1800prsidnt', hello: 'hello world'}
      ]
    });
    

    app/model/TheModel.js

    Ext.define('Test.model.TheModel', {
      extend: 'Ext.data.Model',
      fields: [
        {name: 'name', type: 'string'},
        {name: 'phone', type: 'string'},
        {name: 'hello', type: 'string'}
      ]
    });
    

    app/Utils.js

    Ext.define('Test.Utils', {
      singleton: true,
      requires: ['Test.Utils2'],
      getText: function() {
        return Test.Utils2.hello + 'world';
      }
    });
    

    app/Utils2.js

    Ext.define('Test.Utils2', {
      singleton: true,
      hello: 'hello'
    });
    

    I realize this is a really long example, but I needed to make sure I fully portrayed what I was doing. Utils relies on Utils2 because it needs to call Utils2's hello variable. The rest of the code is setting up a grid and calling the Utils.getText function in TheStore. Firebug throws a Test.Utils is undefined on line 6 in TheStore.js, and at that point in time, Test.Utils obviously doesn't exist, but Test.Utils2 does.

    My question is... why does Utils2 exist, but Utils doesn't? I thought requires brought in the classes that I needed, thus allowing me to use them, but I guess I'm wrong. I've read the Sencha docs and a multitude of threads, but nothing really made sense, and it doesn't really explain this example. Can anyone shed some insight here? I'd appreciate it.

    **Also, I realize I'm doing some dumb things here, but it's merely for an example, so I'm not looking to combine the global Utils or not use globals at all... I'm just trying to figure out the requires option.

    UPDATE

    Thanks to Izhaki's answer below, I figured something out. If I want to use a required class in a class I'm defining, I would have to wait for the object to get created (IE, use initComponent), so my store and grid code changes to:

    app/store/TheStore.js

    Ext.define('Test.store.TheStore', {
      extend: 'Ext.data.Store',
      requires: ['Test.model.TheModel'],
      model: 'Test.model.TheModel'
    });
    

    app/view/TheGrid.js

    Ext.define('Test.view.TheGrid', {
      extend: 'Ext.grid.Panel',
      alias: 'widget.thegrid',
      requires: ['Test.store.TheStore'],
      store: 'TheStore',
      columns: [
        {header: 'Name', dataIndex: 'name'},
        {header: 'Phone', dataIndex: 'phone'},
        {header: 'Hello', dataIndex: 'hello'}
      ],
      // This is the change that works
      initComponent: function() {
        this.callParent();
        this.store.loadData([
          {name: 'keanu reeves', phone: '1800matrices', hello: Test.Utils.getText()},
          {name: 'james earl jones', phone: '1800starwar', hello: 'nothing here'},
          {name: 'barack obama', phone: '1800prsidnt', hello: 'hello world'}
        ]);
      }
    });
    

    This works, but my last question is... do I have to have the requires for TheModel in TheStore, and/or TheStore in TheGrid? It seems like TheController is taking care of all of those requires because I can use Test.Utils in TheGrid, but TheGrid doesn't specifically state that it requires Test.Utils.

    Also, this example from the Sencha docs makes me more confused because I'm clearly not using Test.Utils until TheStore is created, but this example seems like it can use the Child class without having to wait for it to initialize (using initComponent).

  • incutonez
    incutonez almost 12 years
    I like this answer, but there are some things left unexplained (see my updated section of the question).
  • Izhaki
    Izhaki almost 12 years
    As for your first new question: You don't really have to require TheModel in TheStore (specifically as you have it as your in your models config, which is same like requiring it, but you don't get setters and getters with requires). Nor do you need to have require in the TheGrid - as you said, the controller is taking care of all of these.
  • Izhaki
    Izhaki almost 12 years
    Basically when the application launches, it dynamically loads and creates an instance of all the controllers, and all the model/views/stores referenced in the corresponding config objects. Once this is done, all of these come into scope (including the views xtypes).
  • Izhaki
    Izhaki almost 12 years
    The example you gave from the docs is completely fine, same as Test.Util2 within getText is fine - the call to these objects is within a function call (and not reference from a config object), so they only need to be loaded after the class has been created, not before that. A call to getText or giveBirth can only happen after the object was created, which in turn is after the required been dynamically loaded.
  • incutonez
    incutonez almost 12 years
    I think this just about settles it. Thanks for all the explanations!