PDA

View Full Version : Best practices for accessing stores in and out of parent scope



Csegota
18 Jun 2013, 10:32 AM
I am a bit confused as to the best way to implement stores utilizing their getter functions.


One thing I am wondering is what I really gain from adding/loading stores through the use of a stores:[] config in a controller. I understand that it auto generates useful getter methods, but I find myself having to use Ext.create methods, in order to set the store id, in order to reference the store using Ext.getStore('storeId') whenever I go out of scope. And if you use an Ext.create method you dont need to load the store in the store config, because it does all that for you again when you Ext.create it. Leaving me to wonder if I am missing some extra functionality that is provided to loading stores through store configs.


I've been working with Ext JS 4 full time for two months now, and here is what I know about stores and how to access them.


If you place a store within the stores:[] config of a controller. It will auto generate a getter method for you in the form this.getStoreName() (as long as you are in scope)


If you have an 'id' config in your store, you can access you store using Ext.getStore('id') by passing in the stores 'id'. But here is the catch with that one. In order to use that accessor method, you must first have used an Ext.create('myStore') somewhere in your code, I read in a comment somewhere that this is because the id's are set when you use an Ext.create, which seems consistent to me.


So now we have two ways to skin the cat.


Lets say I have some Panel that I am going to load a grid into that requires a store. This panel is already created and is nothing special but a container that I display and remove my content from. So to add my grid I'm going to do it as follows:




//This code is within my controller, because that is where logic should be placed as far as I know.
//This is important to note because the scope will be jumping in and out of the controller within
//some of its functions (which is the underlying cause of my referencing issues).


Ext.getCmp('myPanel').add(
{
xtype: 'myView',
//For the time being, I'm choosing to exclude autoLoad in my store configs.
store: this.getMyStore().load()
}



I think the above code is cool because it utilizes the auto generated store getter method, && allows me to exclude the use of the Ext.create('myStore') method entierly, which in turn will allow me to get rid of my store id's, which I'm almost certain is an unrealistic goal given what I know now.


In another function of my controller, I have a window, which contains a panel, within this panel users are allowed to name a new object and submit it to the grid and store(clicking submit causes the scope to change to the button via the handler), causing a store re load(). Here is the annoying part. Since I originally loaded my store using this.getMyStore().load, calling Ext.getStore('storeId').load() doesn't even work. The get method and the load methods have to MATCH from the original store assignment. So it would seem that this.getMyStore() != Ext.getStore('id') even if they are referencing the same store. So I basically lose the ability to use getMyStore() AND have to add in Ext.create('storeName') somewhere in my code. What’s further, adding in the create method completely negates the benefit of loading a store in a controllers stores[] config, if you are forced to use an Ext.create you can just leave them out of the stores[] config entirely.


So now our code looks like this:




//pseudo code form here on out.
init: function () {
Ext.create('NS.store.MyStore'); //Could place this elsewhere, but oh well.
}
Ext.getCmp('myPanel').add(
{
xtype: 'myView',
store: Ext.getStore('storeId').load()
}
Ext.create(window){
... //config stuff
buttons -> handler: function () {
getForm().submit({
success: Ext.getStore('storeId').load();
}

Notice that the cool getStoreName() method cannot even be used now && there is no longer any reason (as far as I know) to even have stores placed in the controllers stores[] config, since we have to call Ext.create's anyways.


I have some other functions that change scope and require what I would consider a work around in order to access the stores. One is a Ext.each(), one is a messageBox callback. In none of them can I use the this.getMyStore method in because I cant mix getter methods, and I have to be able to access them out of scope of the controller more often than not.


So I guess I should finally get to some concrete questions, now that we are on the same page logically.
1). What is the point of loading stores through a stores:[] config if as soon as you go out of scope, you have to write a line of code like


NAMESPACE.app.getController('ControllerName').getMyStore()

Or your other option is to give your stores id's, and call a prior Ext.create('MyStore'), which again defeats the purpose of even loading stores through the controllers stores:[] config.
2). Am I correct in thinking that the only reason to have an auto generated getter method is to save coding time by not having to write out the long line as in #1 above? ( and not having to write your own getter method, though I'm beginning to wonder if that wouldn’t be more reliable).
3). Is there a way to save a global reference to my parent file so no matter what scope I'm in, I can always just call ref.getMyStore()?
4). What is considered best practice for accessing stores, and am I ever going to be able to get away form using Ext.create calls ( and thus getting rid of store id's) or is that not a plausible or worthy idea?


Thanks in advance for your time and expertise!

slemmon
20 Jun 2013, 12:20 PM
Adding the store to a controller does a few things:
- runs the Ext.define() for the store class
- creates an instance of the store with a storeId of the class name (MyApp.store.Customers would have a storeId of 'Customers' - even if the store had a differently defined storeId config)
- and creates the getter method

The getter method is likely most convenient when working from within the scope of the controller. If the controller's control method is used to handle events (for example, handling the click event on a button instead of having the handler on the button itself) then this.getCustomersStore() may work out to be a convenience for you. If you're not working in the scope of a controller I suspect the most convenient way to fetch the store is to use Ext.getStore('Customers') - which, in this reporter's opinion, is as convenient if not more convenient than than using the created getter method.

If you are configuring a component to use a store and it was included in a controller's stores array then you can configure with that instance of the store using store: 'Customers' - no need to use Ext.create(). If, however, you don't intend to use the the instance created by the controller then, yes, you'll need to create a new instance. You can do so with Ext.create() or if in your store's definition you have an alias (for example - alias: 'store.customers') then you can configure the component with a store 'type' like so store: { type: 'customers' } and in that config object pass any overriding configs for the store you need.

If you're thinking that you don't need a store instance created by the controller and the generated getter method is not-too-convenient you could use a requires: ['MyApp.store.Customers'] in the controller and that will ensure that the store is defined, but the getter and the instance with storeId of 'Customers' will not be created.

As for creating global references what I've seen folks do is in the launch method of the application they'll attach references to the global namespace as needed. So, you could do something like MyApp.getCustomersStore = this.getController('ControllerName').getCustomersStore(). Again, up to you, but since all that does it get a reference to the store with the ID of Customers I'd personally just go with Ext.getStore('Customers').

StoreIds are great for when you need access to a specific store instance. The applications I've worked on in the past were often working with dynamically generated components which would dynamically create stores to go with them and I rarely used storeId's. I'd get a reference to the component and use its getStore() method most of the time. But, it all depends on what your app structure looks like and what helps you manage it most simply.

Csegota
21 Jun 2013, 6:48 AM
Thanks for the in depth answers! That definitely helps me clear up a lot of confusion. I believe your answers paired with passing scope reference arguments when possible will clear up a good amount of my issues.

LesJ
21 Jun 2013, 7:21 AM
Adding the store to a controller does a few things:
- runs the Ext.define() for the store class
- creates an instance of the store with a storeId of the class name (MyApp.store.Customers would have a storeId of 'Customers' - even if the store had a differently defined storeId config)


This is not documented but the store name can include storeId, and this id will be used instead of the name:

myStore@myStoreId


Ext.define('Ext.app.Controller', {
...


/**
* Returns instance of a {@link Ext.data.Store Store} with the given name.
* When store doesn't exist yet, it's created.
*
* @param {String} name
*
* @return {Ext.data.Store} a store instance.
*/
getStore: function(name) {
var storeId, store;


storeId = (name.indexOf('@') == -1) ? name : name.split('@')[0];
store = Ext.StoreManager.get(storeId);


if (!store) {
name = Ext.app.Controller.getFullName(name, 'store', this.$namespace);


if (name) {
store = Ext.create(name.absoluteName, {
storeId: storeId
});
}
}


return store;
},
....