Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

dynamically manage Ext.app.Application.controllers

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
like image 326
jonny Avatar asked Oct 11 '11 12:10

jonny


3 Answers

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)
like image 191
Pavel Podlipensky Avatar answered Nov 07 '22 05:11

Pavel Podlipensky


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:

  • http://docs.sencha.com/ext-js/4-0/#!/guide/class_system
  • http://docs.sencha.com/ext-js/4-0/#!/guide/application_architecture
like image 33
Artur Bodera Avatar answered Nov 07 '22 06:11

Artur Bodera


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.

like image 37
Bradley Avatar answered Nov 07 '22 07:11

Bradley