javascript ExtJS 4 - 在 MVC 架构中重用组件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6111472/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-25 19:31:09  来源:igfitidea点击:

ExtJS 4 - Reuse components in MVC architecture

javascriptextjsextjs4extjs-mvc

提问by Cyril F

I have a list of users and if I click on an item in this list, a window opens. This is the same window for each user, and it's possible to have several window open at the same time. The window shows user informations so for this components I have the same store and the same model.

我有一个用户列表,如果我单击此列表中的一个项目,则会打开一个窗口。这是每个用户的同一个窗口,并且可以同时打开多个窗口。该窗口显示用户信息,因此对于这个组件,我有相同的商店和相同的模型。

But if I load data in a specific window, I load the same data in all other open windows.

但是,如果我在特定窗口中加载数据,则会在所有其他打开的窗口中加载相同的数据。

Ext.define('Cc.view.absence.Grid', {
  extend: 'Ext.grid.Panel',
  alias: 'widget.absencegrid',

  border:false,

  initComponent: function() {
    Ext.apply(this, {
      store: Ext.create('Ext.data.Store', {
        model: 'Cc.model.Absence',
        autoLoad: false,
        proxy: {
          type: 'ajax',
          reader: {
            type: 'json'
          }
        }
      }),
      columns: [
        {header: 'Du', dataIndex: 'startdate', flex: 3, renderer: this.formatDate},
        {header: 'Au', dataIndex: 'enddate', flex: 3, renderer: this.formatDate},
        {header: 'Exercice', dataIndex: 'year', align: 'center', flex: 1},
        {header: 'Statut', xtype:'templatecolumn', tpl:'<img src="../images/status-{statusid}.png" alt="{status}" title="{status}" />', align: 'center', flex: 1},
        {header: 'Type d\'absence', dataIndex: 'absencetype', align: 'center', flex: 2},
        {header: 'Commentaires', dataIndex: 'comment', flex: 6}
      ],
      dockedItems: [{
        xtype: 'toolbar',
        dock: 'top',
        items: [
          { xtype: 'tbfill'},
          { xtype: 'button', text: 'Rafraichir', action: 'refresh', iconCls: 'item-rafraichir' }
        ]
      }]
    });

    this.callParent(arguments);
  },

  formatDate: function(date) {
    if (!date) {
      return '';
    }
    return Ext.Date.format(date, 'l d F Y - H:i');
  }

});

my controller :

我的控制器:

Ext.define('Cc.controller.Absences', {
  extend: 'Ext.app.Controller',

  models: ['Absence', 'AbsenceHistory'],

  views: [],

  refs: [
    { ref: 'navigation', selector: 'navigation' },
    { ref: 'tabPanel', selector: 'tabpanel' },
    { ref: 'absencePanel', selector: 'absencepanel' },
    { ref: 'refreshButton', selector: 'absencepanel button[action=refresh]'},
    { ref: 'absenceGrid', selector: 'absencegrid' },
    { ref: 'absenceHistory', selector: 'absencehistory' },
  ],

  init: function() {
    this.control({
      'absencepanel button[action=refresh]': {
        click: this.onClickRefreshButton
      },
      'absencegrid': {
        selectionchange: this.viewHistory
      },
      'absencegrid > tableview': {
        refresh: this.selectAbsence
      },
    });
  },

  selectAbsence: function(view) {
    var first = this.getAbsenceGrid().getStore().getAt(0);
    if (first) {
      view.getSelectionModel().select(first);
    }
  },

  viewHistory: function(grid, absences) {
    var absence = absences[0],
      store = this.getAbsenceHistory().getGrid().getStore();
    if(absence.get('id')){
      store.getProxy().url = '/absence/' + absence.get('id') +'/history';
      store.load();
    }
  },

  onClickRefreshButton: function(view, record, item, index, e){
    var store = this.getAbsenceGrid().getStore();
    store.load();
  },
});

other controller which create only one instance of absence.Panel :

仅创建一个缺失实例的其他控制器。Panel:

Ext.define('Cc.controller.Tools', {
  extend: 'Ext.app.Controller',

  stores: ['Tools', 'User' ],

  models: ['Tool'],

  views: [],

  refs: [
    { ref: 'navigation', selector: 'navigation' },
    { ref: 'tabPanel', selector: 'tabpanel' },
    { ref: 'toolList', selector: 'toollist' },
    { ref: 'toolData', selector: 'toollist dataview' }
  ],

  init: function() {
    this.control({
      'toollist dataview': {
        itemclick: this.loadTab
      },
    });
  },

  onLaunch: function() {
    var dataview = this.getToolData(),
        store = this.getToolsStore();

    dataview.bindStore(store);
  },

  loadTab: function(view, record, item, index, e){
    var tabPanel = this.getTabPanel();
    switch (record.get('tab')) {
      case 'absences':
        if(Ext.getCmp('absence-panel')){
          tabPanel.setActiveTab(Ext.getCmp('absence-panel'));
        }
        else {
          var panel = Ext.create('Cc.view.absence.Panel',{
            id: 'absence-panel'
          }),
              store = panel.getGrid().getStore();
          panel.enable();
          tabPanel.add(panel);
          tabPanel.setActiveTab(panel);
          store.getProxy().url = '/person/' + this.getUserId() +'/absences';
          store.load();
        }
      break;

      default: 
      break;
    }
  },

  getUserId: function(){
    var userStore = this.getUserStore();
    var id = userStore.first().get('id')
    return id;
  }
});

the other controller which create many instances of absence.Panel :

另一个控制器创建了许多缺席.Panel 实例:

Ext.define('Cc.controller.Agents', {
  extend: 'Ext.app.Controller',

  stores: ['Agents'],

  models: ['Agent', 'Absence', 'AbsenceHistory'],

  views: ['agent.List', 'agent.Window', 'absence.Panel', 'absence.Grid', 'absence.History'],
  refs: [
    { ref: 'agentList', selector: 'agentlist' },
    { ref: 'agentData', selector: 'agentlist dataview' },
    { ref: 'agentWindow', selector: 'agentwindow' },
  ],

  init: function() {
    this.control({
      'agentlist dataview':{
        itemclick: this.loadWindow
      },
    });
  },

  onLaunch: function() {
    var dataview = this.getAgentData(),
        store = this.getAgentsStore();
    dataview.bindStore(store);
  },

  loadWindow: function(view, record, item, index, e){
    if(!Ext.getCmp('agent-window'+record.get('id'))){
      var window = Ext.create('Cc.view.agent.Window', {
        title: 'à propos de '+record.get('firstname')+' '+record.get('lastname'),
        id: 'agent-window'+record.get('id')
      }),
          tabPanel = window.getTabPanel();
          absencePanel = window.getAbsencePanel();
          store = absencePanel.getGrid().getStore();

      absencePanel.enable();
      tabPanel.add(absencePanel);
      tabPanel.setActiveTab(absencePanel);
      store.getProxy().url = '/person/' + record.get('id') +'/absences';
      store.load();
    }
    Ext.getCmp('agent-window'+record.get('id')).show();
  }
});

and the absence.Panel view, container of absence.Grid :

和缺席.面板视图,缺席.网格的容器:

Ext.define('Cc.view.absence.Panel', {
    extend: 'Ext.panel.Panel',
    alias: 'widget.absencepanel',

  title: 'Mes absences',
  iconCls: 'item-outils',
  closable: true,
  border: false,
  disabled: true,
  layout: 'border',

  initComponent: function() {
    this.grid = Ext.create('Cc.view.absence.Grid', {
      region: 'center'
    });
    this.history = Ext.create('Cc.view.absence.History', {
      region: 'south',
      height: '25%'
    });
        Ext.apply(this, {
      items: [
        this.grid,
        this.history
      ]
    });

        this.callParent(arguments);
    },

  getGrid: function(){
    return this.grid;
  },

  getHistory: function(){
    return this.history;
  }
});

回答by Abdel Raoof

Yes. Here is more details explanation of what I am doing. I hope you have read the forum completely. There is still one information that we are not clear about. That is the exact use of using "stores" property in controller. IMHO Sencha team should explain the MVC in much more detail with complex examples.

是的。这是我正在做的事情的更多详细解释。我希望你已经完全阅读了论坛。还有一个信息我们不清楚。这就是在控制器中使用“stores”属性的确切用法。恕我直言,Sencha 团队应该用复杂的例子更详细地解释 MVC。

Yes, what you have newly posted is correct. when you have create new view, create a new instance of the store! Now, from the forum discussions, people argue about MVC. I would definitly go with steffenk. What we are doing here is injecting a new instance of store to my view. And I am ignoring the storesproperty of the controller.

是的,您新发布的内容是正确的。创建新视图后,创建商店的新实例!现在,从论坛讨论中,人们争论 MVC。我肯定会和steffenk一起去。我们在这里所做的是向我的视图中注入一个新的 store 实例。我忽略stores了控制器的属性。

Here is an example:

下面是一个例子:

This is my view. Its a panel (with user profile information) that I display on my tabpanel :

这是我的看法。它是我在 tabpanel 上显示的一个面板(带有用户个人资料信息):

Ext.define('Dir.view.profile.View' ,{
    extend: 'Ext.panel.Panel',
    alias : 'widget.profileview',
    title : 'Profile',
    profileId: 1,   // default and dummy value
    initComponent: function() {

        // configure necessary stuff, I access my store etc here..       
        // console.log(this.profileStore);
        this.callParent(arguments);         
    },
    // Other view methods goes here
});

Now, look at my controller:

现在,看看我的控制器:

Ext.define('Dir.controller.Profile', {
    extend: 'Ext.app.Controller',
    //stores: ['Profile'],   --> Note that I am NOT using this!
    refs: [     
        {ref:'cp',selector: 'centerpane'}
    ],
    views: ['profile.View'],
    init: function() {
        // Do your init tasks if required
    },  
    displayProfile: function(selectedId) {

            // create a new store.. pass your config, proxy url etc..
        var store = Ext.create('Dir.store.Profile',{profileId: selectedId});

        console.log('Display Profile for ID ' + selectedId);    

        // Create instance of my view and pass the new store
        var view = Ext.widget('profileview',{profileId: selectedId,profileStore: store});

        // Add my new view to centeral panel and display it...
        this.getCp().add(view);
        this.getCp().setActiveTab(view);
    }
});

My displayProfile()is called from some event listeners (Menu, Tree etc) and it passes a id. My controller using this id to setup a new store and view. I hope the above code gives you a clear picture of what I said yesterday.

MydisplayProfile()是从一些事件侦听器(菜单、树等)调用的,它传递一个 id。我的控制器使用这个 id 来设置一个新的商店和视图。我希望上面的代码能让你对我昨天所说的有一个清晰的了解。

In your controller, you will have to add Ext.require('Dir.store.Profile');so that ExtJS know you have such a store. This is because we are not making use of storesproperty.

在您的控制器中,您必须添加Ext.require('Dir.store.Profile');以便 ExtJS 知道您有这样的商店。这是因为我们没有使用stores财产。

Now, you can want to reuse these created stores elsewhere, you can add them to the StoreManager. With this, you can access your created stores at any place, add and remove stores. But this comes with a overhead of you managing the instances of the store.

现在,您可能希望在其他地方重用这些创建的商店,您可以将它们添加到StoreManager。有了这个,您可以在任何地方访问您创建的商店,添加和删除商店。但这会带来管理商店实例的开销。



Why do you share the same instance of the store with different views? when you have a new view, create a new instance of the store. This will prevent updated data appearing on other windows when one is refreshed.

为什么你用不同的视图共享同一个 store 实例?当你有一个新的视图时,创建一个 store 的新实例。这将防止更新的数据在刷新时出现在其他窗口上。