在控制器中设置监听器以接收存储事件

29

我有一个控制器,其中包含一个store、一个model和一些视图。

我需要在控制器中监听store的beforesyncwrite事件,但我不知道如何在控制器的control函数中设置这些监听器。

我的store长下面这样:

Ext.define('DT.store.UsersStore', {
    extend : 'Ext.data.Store',
    model : 'DT.model.User',
    id : 'myStore'
    autoSync : true,
    proxy : {
        type : 'ajax',
        api : {
            read : '/load_entries',
            update : '/update_entry'
        },
        reader : {
            type : 'json',
            root : 'user',
            successProperty : 'success'
        }
    }
});

现在我尝试在我的控制器中监听事件:

...
init : function () {
    this.control({
        'myStore' : {
            beforesync : this.doSomething,
            write : this.doSomethingElse
        }
    });
},
...

我期望函数在事件触发时会被执行,但现在它们在事件触发时没有任何反应。

我该如何让它们正常工作?

8个回答

33

你的方法是可行的,但在我看来不是最理想的。更好的方法是使用控制器的store getter。在你的情况下,代码应该像这样:

init : function () {
    // every controller has getters for its stores.
    // For store UsersStore getter would be getUsersStoreStore()
    this.getUsersStoreStore().addListener('write',this.finishedLoading, this);
    this.control({
        // widgets event handlers
    });
},

2
比我的解决方案更好。谢谢,伙计。这个社区真是太棒了。 - Demnogonis
这个解决方案只在使用你定义的控制器的应用程序部分执行代码,是否能够正确工作?或者事件会从此时开始命中这个新的监听器吗? - CDelaney
我认为它只能在这个控制器内部工作,但我不确定,因为我从未在一个应用程序中使用多个控制器。 - Demnogonis
ST2.1 beta中似乎没有任何用于获取存储的getter。 - wprater

19

这里提供一种与 Molecular Man 的回答不同的语法。

与其编写:

init : function () {
    this.getUsersStoreStore().addListener('write',this.finishedLoading, this);
    this.control({
        // widgets event handlers
    });
},
您可以编写
init : function () {
    this.getUsersStoreStore().on({
        write: this.finishedLoading,
        scope: this
    });
    this.control({
        // widgets event handlers
    });
},

我认为这个替代定义读起来更加流畅。

我从一个叫Izhaki的人给我的答案中获取了这个定义。


我们可以使用on()添加多个监听器吗? - aswininayak
2
在这个页面的所有解决方案中,只有 this.getUsersStoreStore().on({.. 对我有效。(使用4.2.1) - Geo

5

关于 Extjs 4.2.1,如果您使用 'storeId' 而不是 id 并且使用 'listen' 函数而不是 'control',您最初访问存储监听器的方式实际上可以工作:

Ext.define('DT.store.UsersStore', {
    extend : 'Ext.data.Store',
    model : 'DT.model.User',
    storeId : 'myStore'
    ....

init : function () {
    this.listen({
        store: {
           '#myStore' : {
               beforesync : this.doSomething,
               ...

4
Ext.define('Store', {
    model: 'Model',
    extend: 'Ext.data.Store',
    listeners: {
        'beforesync': function(){
            App.getController('somecontroller').onBeforeSync();
        }
    }
});

App - 应用程序对象 您可以在控制器中实现onBeforeSync函数...这是我能够将事件分配给存储并仍在控制器中实现逻辑的唯一方法。希望对您有所帮助。


不,这样行不通。this.doSomething 应该执行 console.log('BeforeSync'),但仍然没有任何反应。 - Demnogonis
问题显然在于监听器没有分配给组件。您应该阅读ExtJS中有关查询的文档,该查询用于确定为哪个组件分配事件。尝试类似于“widgetname gridPanel #store”的内容(其中widgetname是分配给控制器的视图)。我目前没有测试的东西,但您应该逐步进行,首先在包含该存储库的组件上添加事件,然后再尝试在存储库上设置事件。 - nscrob
糟糕...我发现存储类既没有id配置也没有别名配置。我的配置将被忽略,控制器中的项目也无法分配。还有其他方法吗? - Demnogonis
我寻找了替代方案,但没有找到。控制函数使用组件查询来获取组件,并且存储它不是一个Ext组件,它扩展了Ext.base,因此我认为不可能使用组件查询来获取存储。我找到了一种替代方法,我将使用我找到的解决方案修改上面的答案。 - nscrob
请不要将您的存储与控制器耦合,这是一个非常糟糕的想法,您无法在应用程序的其他部分重复使用此存储。 - Martin Lantzsch

4
我自己解决了这个问题。
我在我的面板的`render`事件中手动添加了监听器。
Ext.getCmp('userPanel').down('gridpanel').getStore().addListener('write',this.finishedLoading, this);

感谢@nscrob的帮助。

1

希望这个补充能够帮助某些人避免在调试库核心上花费数小时:

与使用控制器的getter方法在控制器内访问Ext.data.Store实例的做法有关:例如,对于上面的“DT.store.UsersStore”,使用this.getUsersStoreStore():

请注意,如果存储器已经与视图相关联(例如,被声明为“UsersGrid” Grid.panel.Panel小部件定义的存储器属性),那么getter方法实际上会检索同一Store类的另一个实例,而不是小部件使用的实例! 原因是将存储器添加到构造函数配置对象中,如下所示:

stores: ['UsersStore']

实际上会在 Ext.data.StoreManager.map 哈希表中添加一个新的存储实例,因此假设目前只有 'UsersStore' 是唯一实例化的 Store 对象,则映射键现在看起来像:

0: "ext-empty-store"
1: "UsersStore"
2: "myStore"

现在想象一下,您想使用存储器代理读取一些新数据,并将这些新数据显示在“UsersGrid”中,当用户单击某个东西时,您希望执行所有这些操作,因此在控制器内部,您将具有用于用户事件处理程序的处理方法,代码如下:
'user-selector' : {
    click: function(){
                     var oStoreReference = this.getUsersStoreStore();
                         oStoreReference.load( {params:{} });
            }
    }

那个获取引用的调用将在内部翻译为 this.getStore('UsersStore'),并返回生成的控制器的引用 - 1:“UsersStore”,而不是 - 2:“myStore”,这可能是人们所期望的。此外,load() 调用将使用新模型加载 UsersStore 实例,但这不会反映在您的网格视图中(因为网格绑定并侦听由“myStore”存储实例生成的事件)。因此,最好通过其 itemId 使用通用 getStore 方法访问存储:this.getStore('storeItemId')。

0
为什么不直接转发store的事件呢?例如:
this.getUsersGrid().relayEvents(this.getUsersStoreStore(), ['write'], 'store')
然后就可以这样做:
this.control('somegrid-selector': {storeWrite: function(){...}})

0

以防万一有人在这里遇到了问题。

ExtJS 7.3

Ext.define('DT.controller.UsersStore', {
    extend: 'Ext.app.Controller',

    listen: {
        store: {
            UsersStore: {
                beforesync : 'doSomething',
                write : 'doSomethingElse'
            }
        }
    },

    doSomething() {
        console.log(arguments)
    },

    doSomethingElse() {
        console.log(arguments)
    }
});

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