Set listener for store events in a controller

Set listener for store events in a controller

I have a controller with a store, a model, and some views.
I need to listen for the beforesync and write event of the store in the controller, but I don’t know how to set these listeners in the controllers control-function.
My store looks like this :
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’
}
}
});

Now I try to listen to the events in my controller :

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

My expected result is that the functions will be executed, when the events are fired.
But at this time nothing happens when they are fired.
How can I get this to work?

Solutions/Answers:

Solution 1:

Your way is possible but it’s not ideal, IMO. The better way is to use controllers’s store getter. In your case the code would be something like this:

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

Solution 2:

Here is an alternative syntax to Molecular Man’s answer.

Related:  Remove element with jQuery but leave text

Instead of writing,

init : function () {
    this.getUsersStoreStore().addListener('write',this.finishedLoading, this);
    this.control({
        // widgets event handlers
    });
},

You can write

init : function () {
    this.getUsersStoreStore().on({
        write: this.finishedLoading,
        scope: this
    });
    this.control({
        // widgets event handlers
    });
},

I think this alternative definition reads a little bit better.

I took this from an answer Izhaki gave me.

Solution 3:

As for Extjs 4.2.1, your initial way of accessing the store listener would actually work, if you were using the ‘storeId’ instead of the id and the ‘listen’ function instead of ‘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,
               ...

Solution 4:

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

App – your application object
The function onBeforeSync you can implement it in the controller … this is the only way i could assign the event to the store and still implement the logic in the controll. I hope it helps

Related:  Converting between strings and ArrayBuffers

Solution 5:

I solved it by myself.

I added the listener manually in the render-event of my Panel

Ext.getCmp('userPanel').down('gridpanel').getStore().addListener('write',this.finishedLoading, this);

Thank you for the help @nscrob.

Solution 6:

Hope this addition will help someone out there to avoid spending some hours on debugging the library core:

Related to this practice of accessing Ext.data.Store instance inside Controller using the controller’s getter method: e.g. for the “DT.store.UsersStore” above using this.getUsersStoreStore():

pay attention that if the store is already associated in a view(e.g. was declared as the store property for a “UsersGrid” Grid.panel.Panel widget definition) then this getter method will retrieve in fact another instance of the same Store class and not the instance used by the widget!
The reason is that adding the store in the constructor configuration object like this:

stores: ['UsersStore']

will in fact add a new store instance in Ext.data.StoreManager.map hash so – supposing that ‘UsersStore’ is the only Store object instantiated so far – the map keys now look like:

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

Now imagine you want to read some new data using your store’proxy and display this new data in the “UsersGrid” and you want to do all these when user clicks on something, so inside controller you will have a handler method for the user event with the code:

'user-selector' : {
    click: function(){
                     var oStoreReference = this.getUsersStoreStore();
                         oStoreReference.load( {params:{} });
            }
    }

That call to get the reference will be translated internally in this.getStore(‘UsersStore’) and will return a reference to the controller generated – 1: “UsersStore” – and not – 2: “myStore” – as one might expected. Furthermore, the load() call will load the UsersStore instance with the new Models and this will not be reflected in your grid view(because the grid is bound and listens to the events generated by “myStore” store instance).

Related:  jQuery trigger file input

So better access the store by its itemId using the general getStore method: this.getStore(‘storeItemId’)

References