ExtJS 5:访问组件中的绑定存储

ExtJS 5: Accessing bound store in component

我真的很难理解如何访问组件上的实际绑定存储实例,例如 ComboBox 或 Grid。看起来,当您使用他们的 getStore 方法时,它 returns 是一个不同的实例。

在我的 example 中,我有一个自定义网格 class,在它的 initComponent 中,我想添加一个加载侦听器。不幸的是,加载监听器永远不会被命中,但绑定存储的加载监听器会。您可以看到监听器是在加载商店之前设置的,所以这不是问题。看起来initComponent中的store实例是一个内存存储,所以此时绑定的store实例没有同步到组件。

我知道我可以在绑定存储上有一个加载监听器,但这是一个自定义网格 class,对于任何自定义网格 class,我希望设置一个监听器...所以我不想在我的代码中到处都这样做...我只想在一个 class 中执行此操作,因为它们都将执行相同的逻辑。

有人可以向我解释为什么我的自定义网格 class 的加载侦听器没有受到影响,我该怎么做才能解决这个问题?我能以某种方式访问​​绑定的商店实例吗?

Ext.application({
  name: 'Fiddle',

  launch: function() {
    Ext.define('MyGrid', {
      extend: 'Ext.grid.Panel',
      xtype: 'myGrid',
      initComponent: function() {
        alert('initComponent')
        this.callParent();
        this.getStore().on('load', this.onLoad, this);
      },
      onLoad: function() {
        alert('grid store loaded');
      }
    });
    Ext.define('MyViewController', {
      extend: 'Ext.app.ViewController',
      alias: 'controller.myview',
      onLoadBoundStore: function() {
        alert('loaded bound');
      }
    })
    Ext.define('MyViewModel', {
      extend: 'Ext.app.ViewModel',
      alias: 'viewmodel.myview',
      stores: {
        myStore: {
          fields: ['name', 'value'],
          autoLoad: true,
          proxy: {
            type: 'ajax',
            url: 'data1.json',
            reader: {
              type: 'json'
            }
          },
          listeners: {
            load: 'onLoadBoundStore'
          }
        }
      }
    });
    Ext.define('MyView', {
      extend: 'Ext.form.Panel',
      renderTo: Ext.getBody(),
      controller: 'myview',
      viewModel: {
        type: 'myview'
      },
      items: [{
        title: 'blah',
        xtype: 'myGrid',
        reference: 'myComboBox',
        bind: {
          store: '{myStore}'
        },
        columns: [{
          text: 'Name',
          dataIndex: 'name'
        }, {
          text: 'Value',
          dataIndex: 'value'
        }]
      }]
    });
    Ext.create('MyView')
  }
});

Can someone explain to me why my custom grid class's load listener is not getting hit, and what can I do to fix this?

您最初没有向您的网格提供任何商店(store config option is required by the way). Hence the grid is creating its own, empty store as coded here:

store = me.store = Ext.data.StoreManager.lookup(me.store || 'ext-empty-store');

那个空的商店是让您的 onLoad 听众附加的商店。它没有被击中,因为商店从未加载过。

Can I somehow access the bound store instance?

是的,使用这个:

this.lookupViewModel().getStore('myStore')

您可以将您的侦听器附加到绑定存储而不是空存储,看看有什么不同。网格的空存储最终会被绑定的存储替换(毕竟这就是您在网格中看到数据的原因),但这发生在 initComponent 执行后。您可以通过覆盖 setStore 方法来跟踪将绑定存储设置到网格的时刻。

I know I can have a load listener on the bound store, but this is a custom grid class, and for any custom grid class, I want there to be a listener set up... so I don't want to have to do this all over the place in my code... I just want it in one class, as they're all going to have the same logic carried out.

由于您使用的是 MVVC,因此建议坚持该模式并保持视图仅声明视图方面。监听器应该在控制器中声明和处理(甚至不像你的例子那样在视图模型中)。否则,如果您继续坚持 Ext JS 5 之前的样式并将动态内容放入视图(即您的情况下的网格),则使用 MVVC 毫无意义。

这太骇人听闻了,我什至不想 post 将它作为答案,但为了 post 诚实起见,我将这样做。基于 Drake 的回答,我想出了如何使用在我的网格 class 的初始配置中传递的内容来获取我的商店。绑定与大括号一起出现,所以这就是我在其上执行 replace 的原因。就像我说的,这可能永远不应该使用,但它确实有用。

initComponent: function() {
  var store = this.lookupViewModel().getStore(this.config.bind.store.replace(/[{}]/g, ''));
  store.on('load', this.onLoad, this);
  this.callParent();
},

只是为了再添加一个选项,您可以在网格上收听 reconfigure 事件,因为这是在绑定商店完成后触发的事件......所以这样的事情会起作用:

Ext.application({
  name: 'Fiddle',

  launch: function() {
    Ext.define('MyGrid', {
      extend: 'Ext.grid.Panel',
      xtype: 'myGrid',
      initComponent: function() {
        alert('initComponent')
        this.on('reconfigure', this.onReconfigureGrid, this);
        this.callParent();
      },
      onReconfigureGrid: function(grid, store, columns, oldStore, oldColumns, eOpts) {
        store.on('load', this.onLoad, this);
      },
      onLoad: function() {
        alert('grid store loaded');
      }
    });
    Ext.define('MyViewController', {
      extend: 'Ext.app.ViewController',
      alias: 'controller.myview',
      onLoadBoundStore: function() {
        alert('loaded bound');
      }
    })
    Ext.define('MyViewModel', {
      extend: 'Ext.app.ViewModel',
      alias: 'viewmodel.myview',
      stores: {
        myStore: {
          fields: ['name', 'value'],
          autoLoad: true,
          proxy: {
            type: 'ajax',
            url: 'data1.json',
            reader: {
              type: 'json'
            }
          },
          listeners: {
            load: 'onLoadBoundStore'
          }
        }
      }
    });
    Ext.define('MyView', {
      extend: 'Ext.form.Panel',
      renderTo: Ext.getBody(),
      controller: 'myview',
      viewModel: {
        type: 'myview'
      },
      items: [{
        title: 'blah',
        xtype: 'myGrid',
        reference: 'myComboBox',
        bind: {
          store: '{myStore}'
        },
        columns: [{
          text: 'Name',
          dataIndex: 'name'
        }, {
          text: 'Value',
          dataIndex: 'value'
        }]
      }]
    });
    Ext.create('MyView');
  }
});