Consider a complex application where you have custom filtering logic and different modes of loading; delayed loading when hidden, no loading when hidden, but load when it's shown and reloading when your custom filters are modified etc.
What part of the mvc app should be responsible for loading, and how to connect it all?
I never found a definitive answer on this from Sencha when I was getting started with MVC but I can tell you what I have been doing for a few apps successfully.
I create and load my stores according to how they are used. That seems to have divided into three different categories for me:
Stores that apply to the whole app
Stores that apply to all instances of a view
Stores that are tied to a single view instance
1. Stores that apply to the whole app
I usually have a "Main" controller that handles the framework of my app, things like keyboard navigation, the main menu, etc.
Stores that fall into the first category above go in this "Main" controller's stores
array. If these stores are not dependent on another store then I simply make them autoLoad: true
and am done with them. But in cases where they are dependent on another stores data then I add a listener to the parent store to load the dependent store inside the parent's onLoad
event.
An example of some of the stores I find falling into this first category are reference stores that I use in comboboxes throughout the app, usually in many different types of views. These are usually configured with autoLoad: true
and then I never load them again for that user's session. Whenever I need a combobox that uses the reference store, I can set it up like this:
{
xtype: 'combobox',
allowBlank: false,
forceSelection: true,
store: Ext.getStore('SomeReferenceStore'),
queryMode: 'local', // this makes sure the store doesn't reload
valueField: 'id',
displayField: 'name'
}
To give an example of two stores that both fall into the first category, with one being dependent on another:
In one of my apps I have a dynamic number of user permissions, when a user logs into the app I needed to fetch the different permissions and modify the User
model to include a boolean field for each of these different permissions:
Ext.define('MyApp.controller.Main', {
extend: 'Ext.app.Controller',
models: [
'User',
'Reference',
// etc...
],
stores: [
'CurrentUser',
'PermissionRef', // this is "autoLoad: true"
// etc...
],
init: function() {
var me = this;
// update the user model and load the user
me.getPermissionRefStore().on('load', function(store, records) {
var model = me.getUserModel(),
fields = model.prototype.fields.getRange();
// append the permissions onto the User model fields
Ext.each(records, function(permission) {
fields.push({
name: permission.get('name'),
type: 'bool',
});
});
// update the user model with the permission fields
model.setFields(fields);
// load the current user
me.getCurrentUserStore().load();
// other stuff...
});
// other stuff...
}
});
With this, whenever I need a reference to the user and what permissions he has available I simply call:
var user = Ext.getStore('CurrentUser').first();
Sometimes a view will also be dependent on a store being loaded. For example my main menu items are determined by a database table, in that case I would include an onLoad
listener the same way (inside the controller's init
function):
// create the menu once we know what menu items are available
me.getMenuStore().on('load', function(store) {
me.getViewport().add(Ext.widget('mainpanel'));
});
The MyApp.store.Menu
itself would be configured with autoLoad: true
.
2. Stores that apply to all instances of a view
I create and load these just like the first category only I put them in the specific view controller's stores
array instead of the "Main" controller stores
array.
Then it's the same basic concept, some are autoLoad: true
some are not if they depend on another store's data.
For the one's that are not autoLoad: true
they get loaded somewhere inside the controller's init
function or as the result of some event being fired.
3. Stores that are tied to a single view instance
Here I may go against the MVC grain, but there really is no better place for a store that applies to a single instance of a view then inside the view itself.
In most cases I don't even put these stores in the view controller's stores
array. I just create and load them inside the view's initComponent
function. As a result of this, when the view gets destroyed, there is no more reference to the store so the store will also get destroyed. That helps slim down on resources for stores that could get created many times.
For example, say you have a MyApp.view.UnicornWeightGrid
that extends a gridpanel
and shows the progressive weight of a unicorn over time. A user can open a UnicornWeightGrid
for all the unicorns in the realm for comparison and cross-reference purposes. There will be as many different instances of the UnicornWeightStore
as there are instances of the UnicornWeightGrid
.
The view could be defined like this:
Ext.define('MyApp.view.UnicornWeightGrid', {
extend: 'Ext.grid.Panel',
alias: 'widget.unicornweight',
requires: [
'MyApp.model.UnicornWeight'
],
closable: true,
initComponent: function() {
var me = this;
me.store = Ext.create('Ext.data.Store', {
model: 'MyApp.model.UnicornWeight',
proxy: {
type: 'ajax',
url: 'unicorns/weight',
extraParams: {
name: me.unicornName
}
}
});
me.store.load();
});
});
Then whenever we want to get a different UnicornWeightGrid
we can simply call:
var grid = Ext.widget('unicornweight', {
unicornName: someUnicornNameVariable
});
myTabPanel.add(grid);
Any onLoad
listeners I need on stores that are defined in a view, I also attach inside the view. So I don't really need a reference anywhere else.
With all that said, this is by no means the only way to set-up your stores.
I have found this to be the most workable way to handle stores consistently in creating a few different ExtJS "MVC" apps, but I sometimes do it differently also in "special" cases.
You should keep in mind that "MVC" is pretty loose design pattern, it is defined and implemented differently in almost every single framework I've used. So you can pretty much do whatever works best for you.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With