PDA

View Full Version : Dynamic models, stores and views - problem with proxy reuse



MaciejZabielski
12 Mar 2013, 8:34 AM
Hi,

I have a dynamically generated tabs with grid panels inside.
First, based on configuration, I create model and register it, then I create a store with configured model, at the end I create a grid panel that has proper column model and has this store connected.

All works fine, but when I create another tab and repeat that (new model if does not exists, new store, new grid) it looks like the store will "reuse" proxy that was created as a first one. So even if I will create 3 grids, each will have different grid.store.model but will have the same grid.store.proxy.model.

Can someone explain why consecutive stores will have proxies build based on initially used proxy (with wrong model?) In that case automatic "setModel" will not replace the model to current one, as the model is already set. The stores are new objects not registered in StoreManager.

I have to call explicitly proxy.setModel(modelName);

I would expect this is a new proxy that does not have anything set? (my store class has a proxy defined by xtype). So every time a new store is created a new proxy is (should be?) created as well?

vadimv
12 Mar 2013, 9:12 AM
Hi,
So every time a new store is created a new proxy is (should be?) created as well?

yes, and it's configured with the config provided in the defined store or model. Post the code.

MaciejZabielski
12 Mar 2013, 12:58 PM
yes you are right, it should and it is - each grid has a separate instance of proxy, so when one proxy is changed the other one remains unchanged. The problem is that next proxies are created based on first.
So that I have
Model A -> create store with Model A -> creates proxy with Model A
Model B -> create store with Model B -> creates proxy with Model A

It's really strange for me or I simply don't understand how ExtJS works behind the scenes. I haven't managed to analyze all of the code in Ext, but I can clearly see, that when the new store is created, it has previous proxy passed instead of "xtype" basic configuration. Than there is a code that creates new instance of proxy based on the first, and because of applyIf - the model is not overridden.

The code that creates the grid looks like this (I have removed most of the relevant code so it is not "working version"


buildGrid: function (schema, tab) { //create data model and colmodel for each metadata field
var modelFields = [];
var colModel = [];
var gridStore, gridPanel, objectModel;
var modelName = "HyperDoc.model.ObjectModel_" + schema.classId;
var modelExists = Ext.ModelManager.isRegistered(modelName);


Ext.each(schema.metadata, function (field, index, fields) {
/*Create model Fields for each metadata field
*/
// A LOT OF CODE FOR EXTRACTING MODEL FIELDS - CREATES ARRAY OF FIELDS
// WE CREATE NEW MODELS ONLY IF THE DO NOT EXISTS
// GRIDS AND STORES ARE CREATED ON DEMAND

/*Create and register model class*/
if (!modelExists) {
objectModel = this.modelFactory(modelName, modelFields);
}
/*Create store using generated model*/gridStore = Ext.create("HyperDoc.store.GridViewStore", {
model: modelName
});
/*Create GridPanel and connect with new Store*/gridPanel = Ext.create("Ext.grid.Panel", {
xtype: 'gridpanel',
header: false,
columns: colModel,
forceFit: true,
store: gridStore,
selType: 'rowmodel',
multiSelect: true,
pendingDict: 0,
preserveScrollOnRefresh: true,
dockedItems: [{
xtype: 'pagingtoolbar',
dock: 'bottom',
displayInfo: true,
store: gridStore
}],


/*Add new grid to its tab*/
tab.add(gridPanel);

/*Set extra parameters for loading data, to be used by Store Build URL function*/
var gridView = tab.up('tslgridview');

var proxy = gridStore.getProxy();
proxy.setModel(modelName); // THIS SHOULD NOT BE NEEDED????
proxy.setExtraParam('childClassId', tab.classId);
proxy.perspId = gridView.perspectiveId;
proxy.classId = gridView.classId;
proxy.objectId = gridView.objectId;



},

Code for the store and proxy: (TslRestProxy is simple extansion to regular RestProxy - that does not change the behavior)


Ext.define('HyperDoc.store.GridViewStore', {
extend: 'Ext.data.Store',
proxy: {
xtype: 'TslRestProxy',
type: 'rest',
url: '../api/perspective/metadata/json',
appendId: false,
remoteSort: true,

buildUrl: function(request) {
/// A LOT OF CODE FOR BUILDING CUSTOM URLS
},

reader: {
type: 'json',
root: 'children',
totalProperty: 'total'
}
}
});

vadimv
12 Mar 2013, 11:37 PM
first error in your code: only components have xtypes, proxies instead have aliases, so in your proxy class just use as is underlined :



Ext.define('Ext.data.proxy.JsonP', {
extend: 'Ext.data.proxy.Server',
alias: ['proxy.jsonp'], // instead of xtype, proxy don't have xtype

MaciejZabielski
13 Mar 2013, 1:08 AM
thanks for pointing that out, but this is not the cause of my problems. It behaves the same with standard rest proxy.

I have changed proxy definition to:

Ext.define('HyperDoc.util.TslRestProxy', {
override : 'Ext.data.proxy.Rest',
alias : 'proxy.tslrest',


an usage to:

Ext.define('HyperDoc.store.GridViewStore', {
extend: 'Ext.data.Store',
proxy: {
//xtype: 'TslRestProxy',
type: 'tslrest',


but now it fails with
Uncaught TypeError: Cannot call method 'substring' of undefined

in parseNamespace: function(namespace) in ExtJS.... :(

The setProxy method is using
proxy = Ext.createByAlias('proxy.' + proxy.type, proxy);
so that should be fine?

vadimv
13 Mar 2013, 2:25 AM
Your proxy definition is wrong, you can't add an alias to an override, if you want to create your own proxy then extend it, don't override it. Fix that and check again, if still have problems lmk and I will look further in your code.

Also I feel you are not known with the ExtJS4 class system, read the guides http://docs.sencha.com/ext-js/4-1/#!/guide, at least the Concepts and Components sections, before coding such things, will save your time and our too, better than fighting with stupid bugs.

MaciejZabielski
13 Mar 2013, 4:44 AM
ok, thanks, I appretiate input about proxy, but we are navigating away from the main problem.
If I use regular proxy, I get the same result, that is in Store constructor, for the first time in function:
me.setProxy(me.proxy || me.model.getProxy());
me.proxy - is a "plain proxy object" taken from class definition.
In the second call, me.proxy is actually a first proxy object that was created - so it has a wrong model set.ok, thanks, I appretiate input about proxy, but we are navigating away from the main problem.

If I use regular proxy, I get the same result, that is in Store constructor, for the first time in function:
me.setProxy(me.proxy || me.model.getProxy());
me.proxy - is a "plain proxy object" taken from class definition.
In the second call, me.proxy is actually a first proxy object that was created - so it has a wrong model set.

Ok, I will put it another way. Why this works: (Each store and proxy has proper model)


gridStore = Ext.create("HyperDoc.store.GridViewStore", {
model: modelName,
proxy: {
type: 'tslrest',
url: '../api/perspective/metadata/json',
appendId: false,
remoteSort: true,

buildUrl: function(request) {
//...
},
reader: {
type: 'json',
root: 'children',
totalProperty: 'total'
}
}
});




Ext.define('HyperDoc.store.GridViewStore', {
extend: 'Ext.data.Store',
requires: [
'HyperDoc.util.TslRestProxy'
]


});


And this does NOT work: (only the first proxy has proper model, next ones are built from the first.


Ext.define('HyperDoc.store.GridViewStore', {
extend: 'Ext.data.Store',
requires: [
'HyperDoc.util.TslRestProxy'
],
proxy: {
type: 'tslrest',
url: '../api/perspective/metadata/json',
appendId: false,
remoteSort: true,

buildUrl: function(request) {
//....
},

reader: {
type: 'json',
root: 'children',
totalProperty: 'total'
}
}
});





gridStore = Ext.create("HyperDoc.store.GridViewStore", {
model: modelName
});

muneer
30 Dec 2014, 10:45 PM
I ran into the exact same issue. This was my workaround:

In my store's beforeload listener, I explicitly set



store.proxy.model = store.model;
store.proxy.reader.model = store.model;

MathewGerard
4 Jun 2015, 12:41 PM
Try to place the Proxy in the Store and not in the Model.