dynamically manage Ext.app.Application.controllers

11,560

Solution 1

The best way for you to use controller on-demand is to load them dynamically and create instances of controllers when needed. Also you need to put your controllers in separate js files, so the schema will be the following:

//let's say you need to use controller User:
var controller = ControllerManager.get('User');//I believe you have some controller manager, similar to Sencha's Ext.ControllerManager
if(controller){
//use it here
}
else {
  loadScript([url of your controller script], controllerLoaded);
}
...
function controllerLoaded(){
//create controller instance here if needed and use it then
}
...
function loadScript(url, callback){

    var script = document.createElement("script")
    script.type = "text/javascript";

    if (script.readyState){  //IE
        script.onreadystatechange = function(){
            if (script.readyState == "loaded" ||
                    script.readyState == "complete"){
                script.onreadystatechange = null;
                callback();
            }
        };
    } else {  //Others
        script.onload = function(){
            callback();
        };
    }

    script.src = url;
    document.getElementsByTagName("head")[0].appendChild(script);
}

UPDATE In order to integrate new controller into already running Ext.app.Application you need to extend Ext.app.Application and add the following method:

addController: function(name){
  //at this point your controller .js file should be already loaded into the DOM  
  var c = this.getController(name); //controller will be created automatically by name in this getter 
  //perform the same initialization steps as it would have during normal ExtJs process
  c.init(this);
  с.onLaunch(this);
}

Btw, instead of using custom method to load javascript file dynamically you can use ExtJs builtin method of Ext.Loader:

/**
         * Load a script file, supports both asynchronous and synchronous approaches
         *
         * @param {String} url
         * @param {Function} onLoad
         * @param {Object} scope
         * @param {Boolean} synchronous
         * @private
         */
        loadScriptFile: function(url, onLoad, onError, scope, synchronous)

Solution 2

Your best bet is to depend on Ext.Loader, but do not use loadScriptFile() method as suggested above.

Ext 4 introduces a class system. One of (many) benefits of that is dep-tree that allows you to manage all your inter-component dependencies and load classes as needed.

Here is how you initialize loader

Ext.Loader.setPath('App','/js/app');
Ext.Loader.setPath('WidgetsLibrary','/js/widgets');
Ext.Loader.setConfig({enabled: true});

Define a dynamically-loaded controller class:

Ext.define('App.controller.Menu', {
    extend: 'Ext.app.Controller',      // leave it as it is
    models: ['Event','User'],          // this assumes App.model.* prefix
    stores: ['Options','Permissions'], // this assumes App.store.* prefix
    views:  ['menu.Bar','SmartButton'],// this assumes App.view.* prefix
    requires: [
        'App.whatever.other.class',    // auto-load this class as a dependency
        'WidgetsLibrary.*',            // auto-load all classes in WidgetsLibrary
    ],

    init: function(){}

 // [...]

Now to dynamically-load your controller class (a mockup):

Ext.require(                   
    'App.controller.Menu',     // this auto-loads all dependencies 
    function(){ 
        // ... as soon as this class 
        //    and all its dependencies have loaded...
        var controller = Ext.create('App.controller.Menu');  // create an instance
        controller.init();                                   // launch init() method
    }
);

BONUS: by using class system and loader, you don't have to maintain your own controller collection and check if controller has been loaded or not. Just use Ext.ClassManager.isCreated() method described here.

if(Ext.ClassManager.isCreated('App.controller.Menu')){
    // ... controller has already been loaded and init ... 
}else{
    // we need to auto-load that controller using Ext.require()
}

More reading:

Solution 3

We just went through this with our webapp. ~250 screens. Yes, we load our controllers dynamically.

Time to build a screen using Ext.JS is about 400% faster than using YUI, which was our previous platform. Nice bit was that we could keep the YUI Connect object which works with better efficiency than the Ext.JS version.

We have an App class that manages the loading and initializing of Ext.JS controllers. Here, we use the only other YUI class in our code which is YUI.get (YUI.get.script). Just make sure you don't load a controller twice in the same session.

I assume you want to dynamically load these controllers for loading time (which is what we struggled with initially too). EXTEND, EXTEND, EXTEND.

Ext.define('namespace.classname', {
{
    extend: 'Ext.form.panel',
    // your code here
}

This will lower your overall code downloading, and speed up the initialization.

Share:
11,560
jonny
Author by

jonny

Updated on June 04, 2022

Comments

  • jonny
    jonny almost 2 years

    At the moment our team evaluate possibility of converting large corporate web-application (kind of a ERP system, 600+ unique screens) using ExtJS for the front end. The application was build on our open sourced eludia engine

    Our engine requires Model definition (it morphs database as you edit definition), have some kind of Controller (Content modules) and Presentation (Presentation modules with code that generates actual js+html mix)

    Like some people from this thread our team has a problem:

    We'd like to have Model and View in server side and just to send JSON-data to the front-end

    Currently eludia core developers(=my team, we maintain both this application and eludia) have done some steps toward morphing engine to use ExtJS as front end

    My team is considering:

    • continue using old Content modules as server side code
    • generating Model files for ExtJS on the fly using server-side Model definition,
    • converting Presentation modules to client-side ExtJS view modules, and write client-side controllers for each screen But now there is one more problem: ExtJS requires to enumerate all controllers in Ext.app.Application Every time a person writes new/ converts a screen from old engine he should add it to this list

    Can Ext.app.Application.controllers ... be generated dynamically?

    Therefore these questions, ordered by fuzziness:

    • Can you name any large enough (600+ screens, preferable open-sourced) MVC/non MVC application which uses ExtJS as front-end ?
    • Are we moving in the right way?

    UPDATE

    I should try to narrow question

    One doesn't need to load all controllers at once during app startup?

    What I trying to say, maybe it is possible to load controllers in a more 'dynamic' approach:

    • generate one controller js for opened screen
    • append new ones to Ext.app.Application.controllers whenever user does something (clicks a link, button, etc.): when new screen is needed
  • jonny
    jonny over 12 years
    I know how to create/load contoller, I am just not sure how to 'plug it in' in running ExtJS application
  • jonny
    jonny over 12 years
    here is man doing something similar to what I want: stackoverflow.com/questions/6290729/… good point, will look into it, thanks!