使用多个控制器与ExtJS 4 MVC模式

8
假设我有一个主控制器,那么我的应用程序每个"模块"都有一个控制器。这个主控制器包含视口,然后是一个带菜单的标题+一个"居中"的容器,一开始是空的。
菜单中的点击将更改当前模块/控制器,然后该控制器所属的即席视图将显示在居中的容器中。
我认为这是一个非常简单的场景,但奇怪的是我没有找到正确的方法来实现它。有什么建议吗?非常感谢!
2个回答

9

以下是我的工作内容:我有一个顶部的工具栏,一个左侧导航和中心位置是工作区(基本上是选项卡面板),就像你所提到的。让我们分别来看一下应用程序的各个部分并进行解释。首先,这是我的视口外观:

Ext.define('App.view.Viewport',{
    extend: 'Ext.container.Viewport', 
    layout: 'border',
    requires: [
        'App.view.menu.NavigationPane',
        'App.view.CenterPane',          
        'App.view.menu.Toolbar'
    ], 
    initComponent: function() {
        Ext.apply(this, {
            items: [{
                region: 'north',
                xtype: 'panel',                 
                height: 24,                                     
                tbar: Ext.create('App.view.menu.Toolbar')                                       
            },{
                title: 'Navigation Pane',
                region: 'west',
                width: 200,
                layout: 'fit',
                collapsible: true, 
                collapsed: true,
                items: Ext.create('App.view.menu.NavigationPane')                                       
            },{
                region: 'center',                                               
                xtype: 'centerpane'                                     
            }]       
         });

        this.callParent(arguments);
     }
});

您可以看到我有一个工具栏(App.view.menu.Toolbar),其中包含菜单和左侧导航(App.view.menu.NavigationPane)。这两个组件构成了我的主菜单或通往其他模块的入口。用户选择菜单项,适当的模块视图(如表单、网格、图表等)将加载到“centerpane”中。Centerpane只是Ext.tab.Panel的一个派生类。
正如您所说,我有一个主控制器来处理来自工具栏和导航窗格的所有请求。它仅处理工具栏和导航窗格的点击操作。以下是我的AppController:
Ext.define('CRM.controller.AppController',{
    extend: 'Ext.app.Controller',    
    init: function() {

        this.control({   

            'apptoolbar button[action="actionA"]' : {
                     click : function(butt,evt) {
                             this.application.getController('Controller1').displayList();
                     }
             },  
             .
             .  // Add all your toolbar actions & navigation pane's actions...
             .           
             'apptoolbar button[action="actionB"]' : {
                     click : function(butt,evt) {
                            this.application.getController('Controller2').NewRequest(); 
                     }
             }
        });     
     } 
 });

看一下我的一个按钮处理器。我通过'application'属性获取控制器:

this.application.getController('Controller2').NewRequest(); 

借助 getController 方法,我获取控制器的实例,然后调用控制器内任意方法。现在让我们看一下我模块控制器的框架:
Ext.define('CRM.controller.Controller2',{
    extend: 'Ext.app.Controller',    
    refs: [         
        {ref:'cp',selector: 'centerpane'}, // reference to the center pane
        // other references for the controller
    ],
    views: ['c2.CreateForm','c2.EditForm','c2.SearchForm','c2.SearchForm'],
    init: function() {

        this.control({   

            'newform button[action="save"]' : {
                // Do save action for new item
            },  
            'editform button[action="save"]' : {
                // update the record...
            },  
            'c2gridx click' : {
                // oh! an item was click in grid view
             }
        });     
    },
    NewRequest: function() {
        var view = Ext.widget('newform');
        var cp = this.getCp();      // Get hold of the center pane... 
        cp.add(view);   
        cp.setActiveTab(view);
    },
    displayList: function() {
        // Create grid view and display...
    }   
 });

我的模块控制器仅包含与该模块相关的操作(模块的网格、表单等)。这应该有助于您开始朝着正确的方向推进。


谢谢您的详细解释,但是我仍然有问题。请查看我对之前回答(techknowfreak)的评论。 - TigrouMeow
抱歉,我没听懂你的意思。所谓的子控制器在哪里知道父控制器?你能详细说明一下吗?在上述代码中,模块控制器没有与主控制器开始任何交互,对吗?还是我理解错了.. :) - Abdel Raoof Olakara
1
抱歉,子控制器不知道关于“_父视图_”(这里是'centerpane')的事情。我希望模块(一组控制器+视图)可以独立运行。 - TigrouMeow

1
在主控制器中,在菜单的点击事件处理程序中添加子控制器。
Ext.define('MyAPP.controller.MainController',{
...
  init:function()
  {
    this.control({
     'menulink':
     {
        click:this.populateCenterPanel
     }
    });
  },
  populateCenterPanel:function()
  {
    this.getController('ChildController');
  }
});

在启动函数中,向控制器添加监听器并添加事件,如下所示 -
Ext.application({
...
  launch:function(){
    this.controllers.addListener('add',this.newControllerAdded,this);
  },

  newControllerAdded:function(idx, ctrlr, token){
    ctrlr.init();
  }
});

现在将动态嵌入视图的代码放置在ChildController的init方法中。
Ext.define('MyAPP.controller.ChildController',{
...
  refs: [
    {ref:'displayPanel',selector:'panel[itemId=EmbedHere]'}
  ]
  init:function(){
    var panel=this.getDisplayPanel();
    panel.removeAll();
    panel.add({
      xtype:'mycustomview',
      flex:1,
      autoHeight:true,
      ...
    });
  }
});

HTH :)


这也是我想到的主意,问题是我希望避免子控制器知道它的父控制器是谁。这有点像婴儿在出生之前选择他的父母,对吧? :p - TigrouMeow
使用应用程序事件...让主控制器在菜单被点击时触发应用程序事件,然后子控制器处理它。 - techknowfreak
1
这就是我现在所做的,我将“主容器”的ID传递给控制器,以便我可以正确使用“this.control”和“refs”。尽管如此,我仍然认为这是很多小技巧,我希望所有这些都可以由框架动态管理 :( - TigrouMeow

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接