动态管理Ext.app.Application.controllers

时间:2011-10-11 12:19:25

标签: model-view-controller extjs frontend

目前,我们的团队正在评估使用ExtJS作为前端转换大型企业网络应用程序(一种ERP系统,600多种独特屏幕)的可能性。该应用程序基于我们的开源eludia引擎

我们的引擎需要模型定义(它在编辑定义时变形数据库),有某种控制器 (内容模块)和演示文稿(包含生成实际js + html混合的代码的演示模块)

与某些来自this线程的人一样,我们的团队遇到了问题:

我们希望在服务器端拥有模型和视图,只是将JSON数据发送到前端

目前,eludia核心开发人员(=我的团队,我们维护此应用程序和eludia)已经采取了一些步骤来变形引擎以使用ExtJS作为前端

我的团队正在考虑:

  • 继续使用旧的内容模块作为服务器端代码
  • 使用服务器端模型定义
  • 动态生成ExtJS的模型文件
  • 将Presentation模块转换为客户端ExtJS视图模块,并为每个屏幕编写客户端控制器 但现在还有一个问题:ExtJS需要枚举Ext.app.Application中的所有控制器 每当一个人从旧引擎写新/转换屏幕时,他应该将其添加到此列表

可以动态生成Ext.app.Application.controllers吗?

因此,这些问题由模糊性排序:

  • 你能说出任何使用ExtJS作为前端的足够大(600多个屏幕,最好的开源)MVC /非MVC应用吗?
  • 我们正在以正确的方式前进吗?

更新

我应该尝试缩小问题

在应用启动期间,您不需要一次加载所有控制器吗?

我想说的是,也许可以用更“动态”的方式加载控制器:

  • 为打开的屏幕生成一个控制器js
  • 将新的附加到Ext.app.Application.controllers 每当用户做某事时(点击链接,按钮等):当需要新屏幕时

5 个答案:

答案 0 :(得分:6)

按需使用控制器的最佳方法是动态加载它们并在需要时创建控制器实例。您还需要将控制器放在单独的js文件中,因此架构将如下所示:

//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);
}

<强>更新 要将新控制器集成到已运行的Ext.app.Application中,您需要扩展Ext.app.Application并添加以下方法:

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);
}

顺便说一句,不是使用自定义方法动态加载javascript文件,而是可以使用Ext.Loader的ExtJs内置方法:

/**
         * 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)

答案 1 :(得分:6)

您最好的选择取决于Ext.Loader,但使用上述建议的loadScriptFile()方法。

Ext 4引入了一个类系统。这种(许多)好处之一是dep-tree,它允许您根据需要管理所有组件间依赖关系和加载类。

以下是初始化加载程序的方法

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

Define动态加载的控制器类:

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(){}

 // [...]

现在到dynamically-load你的控制器类(一个模型):

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:通过使用类系统和加载器,您不必维护自己的控制器集合并检查控制器是否已加载。只需使用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()
}

更多阅读:

答案 2 :(得分:1)

我们刚刚使用我们的webapp进行了此操作。 ~250个屏幕。是的,我们动态加载我们的控制器。

使用Ext.JS构建屏幕的时间比使用YUI(我们之前的平台)快约400%。好的一点是,我们可以保留YUI Connect对象,其工作效率比Ext.JS版本更好。

我们有一个App类来管理Ext.JS控制器的加载和初始化。在这里,我们在代码中使用唯一的其他YUI类,即YUI.get(YUI.get.script)。只需确保在同一会话中不加载控制器两次。

我假设你想动态加载这些控制器以加载时间(这也是我们最初也在努力解决的问题)。 EXTEND,EXTEND,EXTEND。

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

这会降低整体代码下载速度,并加快初始化速度。

答案 3 :(得分:0)

虽然我不知道这是否有效(从未尝试过),但我要看的是Ext.app.Application.getController()方法。来自api reference

  

返回具有给定名称的控制器的实例。当控制器尚不存在时,它就被创建了。

理论上,您可以使用动态定义的控制器调用getController()并创建它。

一方面注意到我在查看Ext 4时学到了什么。控制器无法触发事件,因此在控制器之间进行通信所需要做的就是在Application对象上触发事件,如{{3 }}

答案 4 :(得分:0)

我在这里问了同样的问题:http://www.sencha.com/forum/showthread.php?151220-Adding-controllers-views-dynamically-in-Ext-MVC-pattern

在当前的Ext 4中似乎不支持这种情况。我已经改变方向并且没有使用Ext提供的MVC架构,而是使用我在Ext 3中使用的相同技术,即添加/在某些处理程序上加载其他组件(按钮或链接点击,悬停,搜索等)。

在我的应用程序中,我的所有组件都是基本Ext类的自定义扩展,并且最终的行为很像控制器,超类是视图。例如,如果我的扩展名为Ext.panel.Panel,除了itemslayout的初始配置之外,我没有做任何影响视图的事情(这都是在基类中处理的) )。大多数类都将处理程序和其他东西附加到面板以提供特定于应用程序的行为,这基本上是控制器的定义。它并不完美,但在我看来,它比目前的替代方案更好。

如果您想要我所谈论的任何示例,或对我的具体实施有疑问,请告诉我,我将很乐意为您提供帮助。