PDA

View Full Version : [FIXED][3.1] baseParams and no params issue



pcr
21 Dec 2009, 3:19 AM
Hi another issues with ExtJS 3.1.0 is that the baseparams are not passed to the backend. With ExtJS 3.0.3 everything is OK. I traced what happens in firebug. If the on.('beforeload') is fired the baseParams are filled. I can see them in the grid.baseParams. Then I watched the POST in the Console of firebug, but the baseParams are not passed to the backend.

I remember this problems also occured in from the start with ExtJS 3.0. So maybe this a bug that was solved and happens again in 3.1.0. I posted this and the reply from the team was I was right. It was a bug resloved in 3.0.3


Let me say ExtJS 3.1.0 is much faster than ExtJS 3.0.3. is very true. Great work.

Animal
21 Dec 2009, 3:30 AM
GridPanel does not have a baseParams property.

Fredric Berling
21 Dec 2009, 4:50 AM
I have the same issueas PCR.. When i change baseparameters for a store in a listener on the beforeload event, these baseparams are not sent on the store load. if i call load a second time it works fine (the baseparams are actualy changed and sent). This is consistant on all uses of beforeload in my current application, and worked well in 3.0.0.

rblon
21 Dec 2009, 4:55 AM
regarding baseParams: I actually observed that when a parameter is an array, that in Ext 3.1 it is being passed even if it is empty, while in Ext 3.0 that was not the case. I had some code which was breaking because of this (but that could be easily solved by changing the serverside).

EDIT:
I DO observe the same problem as PCR and Fredric are reporting. setBaseParam in beforeload event doesn't seem to work

hendricd
21 Dec 2009, 11:28 AM
regarding baseParams: I actually observed that when a parameter is an array, that in Ext 3.1 it is being passed even if it is empty, while in Ext 3.0 that was not the case. I had some code which was breaking because of this (but that could be easily solved by changing the serverside).

EDIT:
I DO observe the same problem as PCR and Fredric are reporting. setBaseParam in beforeload event doesn't seem to work


I have the same issueas PCR.. When i change baseparameters for a store in a listener on the beforeload event, these baseparams are not sent on the store load. if i call load a second time it works fine (the baseparams are actualy changed and sent). This is consistant on all uses of beforeload in my current application, and worked well in 3.0.0.


Hi another issues with ExtJS 3.1.0 is that the baseparams are not passed to the backend. With ExtJS 3.0.3 everything is OK. I traced what happens in firebug. If the on.('beforeload') is fired the baseParams are filled. I can see them in the grid.baseParams. Then I watched the POST in the Console of firebug, but the baseParams are not passed to the backend.

I remember this problems also occured in from the start with ExtJS 3.0. So maybe this a bug that was solved and happens again in 3.1.0. I posted this and the reply from the team was I was right. It was a bug resloved in 3.0.3


Let me say ExtJS 3.1.0 is much faster than ExtJS 3.0.3. is very true. Great work.

Can either (or all) post your beforeload listener and store config for review?

mschwartz
21 Dec 2009, 12:49 PM
Using a DataStore with JsonReader. On render, I call store.reload() and no parameters are posted to the server. I do have a beforeLoad listener that sets baseParams, but those aren't being sent.

I step into reload() and see that it is doing this:


20293 this.load(Ext.applyIf(options||{}, this.lastOptions));


Options is undefined and obviously this.lastOptions is {}

I am not seeing that baseParams is being honored at all.

hendricd
21 Dec 2009, 12:59 PM
Applicable duplicate posts merged here for clarity...

hendricd
21 Dec 2009, 1:56 PM
Fixed in trunk SVN 5803.

rblon
21 Dec 2009, 3:33 PM
Is it possible to post the fix as an override?
I would consider this a major bug. Many of my dataStores use setBaseParams in the beforeload event, and I imagine I am not the only one. Does your release cycle mean the fix will only be available in 3 months?

pcr
21 Dec 2009, 4:11 PM
I agree with RBLON. Please let us know how we can fix ExtJS 3.1.0 with a patch or override. Else I have to go back to release 3.0.3. I do need the speedimprovements in 3.1.0.

After I posted this problems some months ago with the start of ExtJS 3.0 I had to wait some months for a new public release. I hope this is not the case this time.

I agree this is a major bug. It makes ExtJS unreliable. I use a lot of filtering grids by setting baseParams. Because the baseParams are not passed the grids are not filtered properly.

pcr
21 Dec 2009, 4:15 PM
By the way. Thank you HENDRICD for the quick response about this bug and fix. You are doing great work on ExtJS.

hendricd
21 Dec 2009, 4:55 PM
Here is an equivalent override for Ext 3.1. It is not compat with Ext 3.0.x.



Ext.override(Ext.data.Store, {

constructor : function(config){
this.data = new Ext.util.MixedCollection(false);
this.data.getKey = function(o){
return o.id;
};

// temporary removed-records cache
this.removed = [];

if(config && config.data){
this.inlineData = config.data;
delete config.data;
}

Ext.apply(this, config);

/**
* See the <code>{@link #baseParams corresponding configuration option}</code>
* for a description of this property.
* To modify this property see <code>{@link #setBaseParam}</code>.
* @property
*/
this.baseParams = Ext.isObject(this.baseParams) ? this.baseParams : {};

this.paramNames = Ext.applyIf(this.paramNames || {}, this.defaultParamNames);

if((this.url || this.api) && !this.proxy){
this.proxy = new Ext.data.HttpProxy({url: this.url, api: this.api});
}
// If Store is RESTful, so too is the DataProxy
if (this.restful === true && this.proxy) {
// When operating RESTfully, a unique transaction is generated for each record.
// TODO might want to allow implemention of faux REST where batch is possible using RESTful routes only.
this.batch = false;
Ext.data.Api.restify(this.proxy);
}

if(this.reader){ // reader passed
if(!this.recordType){
this.recordType = this.reader.recordType;
}
if(this.reader.onMetaChange){
this.reader.onMetaChange = this.reader.onMetaChange.createSequence(this.onMetaChange, this);
}
if (this.writer) { // writer passed
if (this.writer instanceof(Ext.data.DataWriter) === false) { // <-- config-object instead of instance.
this.writer = this.buildWriter(this.writer);
}
this.writer.meta = this.reader.meta;
this.pruneModifiedRecords = true;
}
}

/**
* The {@link Ext.data.Record Record} constructor as supplied to (or created by) the
* {@link Ext.data.DataReader Reader}. Read-only.
* <p>If the Reader was constructed by passing in an Array of {@link Ext.data.Field} definition objects,
* instead of a Record constructor, it will implicitly create a Record constructor from that Array (see
* {@link Ext.data.Record}.{@link Ext.data.Record#create create} for additional details).</p>
* <p>This property may be used to create new Records of the type held in this Store, for example:</p><pre><code>
// create the data store
var store = new Ext.data.ArrayStore({
autoDestroy: true,
fields: [
{name: 'company'},
{name: 'price', type: 'float'},
{name: 'change', type: 'float'},
{name: 'pctChange', type: 'float'},
{name: 'lastChange', type: 'date', dateFormat: 'n/j h:ia'}
]
});
store.loadData(myData);

// create the Grid
var grid = new Ext.grid.EditorGridPanel({
store: store,
colModel: new Ext.grid.ColumnModel({
columns: [
{id:'company', header: 'Company', width: 160, dataIndex: 'company'},
{header: 'Price', renderer: 'usMoney', dataIndex: 'price'},
{header: 'Change', renderer: change, dataIndex: 'change'},
{header: '% Change', renderer: pctChange, dataIndex: 'pctChange'},
{header: 'Last Updated', width: 85,
renderer: Ext.util.Format.dateRenderer('m/d/Y'),
dataIndex: 'lastChange'}
],
defaults: {
sortable: true,
width: 75
}
}),
autoExpandColumn: 'company', // match the id specified in the column model
height:350,
width:600,
title:'Array Grid',
tbar: [{
text: 'Add Record',
handler : function(){
var defaultData = {
change: 0,
company: 'New Company',
lastChange: (new Date()).clearTime(),
pctChange: 0,
price: 10
};
var recId = 3; // provide unique id
var p = new store.recordType(defaultData, recId); // create new record
grid.stopEditing();
store.{@link #insert}(0, p); // insert a new record into the store (also see {@link #add})
grid.startEditing(0, 0);
}
}]
});
* </code></pre>
* @property recordType
* @type Function
*/

if(this.recordType){
/**
* A {@link Ext.util.MixedCollection MixedCollection} containing the defined {@link Ext.data.Field Field}s
* for the {@link Ext.data.Record Records} stored in this Store. Read-only.
* @property fields
* @type Ext.util.MixedCollection
*/
this.fields = this.recordType.prototype.fields;
}
this.modified = [];

this.addEvents(
/**
* @event datachanged
* Fires when the data cache has changed in a bulk manner (e.g., it has been sorted, filtered, etc.) and a
* widget that is using this Store as a Record cache should refresh its view.
* @param {Store} this
*/
'datachanged',
/**
* @event metachange
* Fires when this store's reader provides new metadata (fields). This is currently only supported for JsonReaders.
* @param {Store} this
* @param {Object} meta The JSON metadata
*/
'metachange',
/**
* @event add
* Fires when Records have been {@link #add}ed to the Store
* @param {Store} this
* @param {Ext.data.Record[]} records The array of Records added
* @param {Number} index The index at which the record(s) were added
*/
'add',
/**
* @event remove
* Fires when a Record has been {@link #remove}d from the Store
* @param {Store} this
* @param {Ext.data.Record} record The Record that was removed
* @param {Number} index The index at which the record was removed
*/
'remove',
/**
* @event update
* Fires when a Record has been updated
* @param {Store} this
* @param {Ext.data.Record} record The Record that was updated
* @param {String} operation The update operation being performed. Value may be one of:
* <pre><code>
Ext.data.Record.EDIT
Ext.data.Record.REJECT
Ext.data.Record.COMMIT
* </code></pre>
*/
'update',
/**
* @event clear
* Fires when the data cache has been cleared.
* @param {Store} this
* @param {Record[]} The records that were cleared.
*/
'clear',
/**
* @event exception
* <p>Fires if an exception occurs in the Proxy during a remote request.
* This event is relayed through the corresponding {@link Ext.data.DataProxy}.
* See {@link Ext.data.DataProxy}.{@link Ext.data.DataProxy#exception exception}
* for additional details.
* @param {misc} misc See {@link Ext.data.DataProxy}.{@link Ext.data.DataProxy#exception exception}
* for description.
*/
'exception',
/**
* @event beforeload
* Fires before a request is made for a new data object. If the beforeload handler returns
* <tt>false</tt> the {@link #load} action will be canceled.
* @param {Store} this
* @param {Object} options The loading options that were specified (see {@link #load} for details)
*/
'beforeload',
/**
* @event load
* Fires after a new set of Records has been loaded.
* @param {Store} this
* @param {Ext.data.Record[]} records The Records that were loaded
* @param {Object} options The loading options that were specified (see {@link #load} for details)
*/
'load',
/**
* @event loadexception
* <p>This event is <b>deprecated</b> in favor of the catch-all <b><code>{@link #exception}</code></b>
* event instead.</p>
* <p>This event is relayed through the corresponding {@link Ext.data.DataProxy}.
* See {@link Ext.data.DataProxy}.{@link Ext.data.DataProxy#loadexception loadexception}
* for additional details.
* @param {misc} misc See {@link Ext.data.DataProxy}.{@link Ext.data.DataProxy#loadexception loadexception}
* for description.
*/
'loadexception',
/**
* @event beforewrite
* @param {Ext.data.Store} store
* @param {String} action [Ext.data.Api.actions.create|update|destroy]
* @param {Record/Array[Record]} rs
* @param {Object} options The loading options that were specified. Edit <code>options.params</code> to add Http parameters to the request. (see {@link #save} for details)
* @param {Object} arg The callback's arg object passed to the {@link #request} function
*/
'beforewrite',
/**
* @event write
* Fires if the server returns 200 after an Ext.data.Api.actions CRUD action.
* Success of the action is determined in the <code>result['successProperty']</code>property (<b>NOTE</b> for RESTful stores,
* a simple 20x response is sufficient for the actions "destroy" and "update". The "create" action should should return 200 along with a database pk).
* @param {Ext.data.Store} store
* @param {String} action [Ext.data.Api.actions.create|update|destroy]
* @param {Object} result The 'data' picked-out out of the response for convenience.
* @param {Ext.Direct.Transaction} res
* @param {Record/Record[]} rs Store's records, the subject(s) of the write-action
*/
'write',
/**
* @event beforesave
* Fires before a save action is called. A save encompasses destroying records, updating records and creating records.
* @param {Ext.data.Store} store
* @param {Object} data An object containing the data that is to be saved. The object will contain a key for each appropriate action,
* with an array of records for each action.
*/
'beforesave',
/**
* @event save
* Fires after a save is completed. A save encompasses destroying records, updating records and creating records.
* @param {Ext.data.Store} store
* @param {Number} batch The identifier for the batch that was saved.
* @param {Object} data An object containing the data that is to be saved. The object will contain a key for each appropriate action,
* with an array of records for each action.
*/
'save'

);

if(this.proxy){
// TODO remove deprecated loadexception with ext-3.0.1
this.relayEvents(this.proxy, ['loadexception', 'exception']);
}
// With a writer set for the Store, we want to listen to add/remove events to remotely create/destroy records.
if (this.writer) {
this.on({
scope: this,
add: this.createRecords,
remove: this.destroyRecord,
update: this.updateRecord,
clear: this.onClear
});
}

this.sortToggle = {};
if(this.sortField){
this.setDefaultSort(this.sortField, this.sortDir);
}else if(this.sortInfo){
this.setDefaultSort(this.sortInfo.field, this.sortInfo.direction);
}

Ext.data.Store.superclass.constructor.call(this);

if(this.id){
this.storeId = this.id;
delete this.id;
}
if(this.storeId){
Ext.StoreMgr.register(this);
}
if(this.inlineData){
this.loadData(this.inlineData);
delete this.inlineData;
}else if(this.autoLoad){
this.load.defer(10, this, [
typeof this.autoLoad == 'object' ?
this.autoLoad : undefined]);
}
// used internally to uniquely identify a batch
this.batchCounter = 0;
this.batches = {};
},

execute : function(action, rs, options, /* private */ batch) {
// blow up if action not Ext.data.CREATE, READ, UPDATE, DESTROY
if (!Ext.data.Api.isAction(action)) {
throw new Ext.data.Api.Error('execute', action);
}
// make sure options has a fresh, new params hash
options = Ext.applyIf(options||{}, {
params: {}
});
if(batch !== undefined){
this.addToBatch(batch);
}
// have to separate before-events since load has a different signature than create,destroy and save events since load does not
// include the rs (record resultset) parameter. Capture return values from the beforeaction into doRequest flag.
var doRequest = true;

if (action === 'read') {
doRequest = this.fireEvent('beforeload', this, options);
Ext.applyIf(options.params, this.baseParams);
}
else {
// if Writer is configured as listful, force single-record rs to be [{}] instead of {}
// TODO Move listful rendering into DataWriter where the @cfg is defined. Should be easy now.
if (this.writer.listful === true && this.restful !== true) {
rs = (Ext.isArray(rs)) ? rs : [rs];
}
// if rs has just a single record, shift it off so that Writer writes data as '{}' rather than '[{}]'
else if (Ext.isArray(rs) && rs.length == 1) {
rs = rs.shift();
}
// Write the action to options.params
if ((doRequest = this.fireEvent('beforewrite', this, action, rs, options)) !== false) {
this.writer.apply(options.params, this.baseParams, action, rs);
}
}
if (doRequest !== false) {
// Send request to proxy.
if (this.writer && this.proxy.url && !this.proxy.restful && !Ext.data.Api.hasUniqueUrl(this.proxy, action)) {
options.params.xaction = action; // <-- really old, probaby unecessary.
}
// Note: Up until this point we've been dealing with 'action' as a key from Ext.data.Api.actions.
// We'll flip it now and send the value into DataProxy#request, since it's the value which maps to
// the user's configured DataProxy#api
// TODO Refactor all Proxies to accept an instance of Ext.data.Request (not yet defined) instead of this looooooong list
// of params. This method is an artifact from Ext2.
this.proxy.request(Ext.data.Api.actions[action], rs, options.params, this.reader, this.createCallback(action, rs, batch), this, options);
}
return doRequest;
}
});
This permits the following in the beforeload listener:



store.on('beforeload', function(store, options){

store.setBaseParam('foo', 'bar');

// and/or

Ext.apply(options.params, {
foos : 'bars'
});

// or

store.baseParams = { // works, but you SHOULD use the setter (setBaseParam above) instead.
foo : 'bar'
};

});
But, just a reminder: baseParams are common values intended for every store request (eg. sessionId, userId etc). Adjusting options.params (as shown above) is still the recommended way to augment per-request params with a beforeload listener (since they enjoy final precedence).

Fredric Berling
21 Dec 2009, 11:19 PM
Thanks Henricd .. I hadnt grasped the real meaning of baseParam compared to options.params . Quick response and a solution in just a day is perfect. And i would like to thank the Ext team for this great release.

pcr
22 Dec 2009, 2:17 AM
Thanks Hendricd. Especially for the quick service. I tested and the result is great. You make my day.
Just to make sure your explanation about use of baseParams and params. This is what I often did in my application:

I have a grid called 'Incidents'. Now I want to show in a tab a grid with incidents with 'status' is new. I instantiate a incident grid to newincident and add a on('beforeload') to set baseParams to this newincident grid to filter records with status = new. So this newincident grid always shows only 'new' records. Is this the proper way to use baseParams or should I use params??

rblon
22 Dec 2009, 3:46 AM
But, just a reminder: baseParams are common values intended for every store request (eg. sessionId, userId etc). Adjusting options.params (as shown above) is still the recommended way to augment per-request params with a beforeload listener (since they enjoy final precedence).

Agreed, so any parameter that goes with every request should be a baseParam. In my case some of them need to be (re)set with every store load.

It seems that when I change, in the beforeload event, every instance of


store.setBaseParam('foo', 'bar');

to


Ext.apply(options.params, {foo : 'bar'});

it works as "params will override any baseParams of the same name".

So guess I will be using that workaround for now instead of the override. Or do you think there is any downside compared to using setBaseParam?

hendricd
23 Dec 2009, 10:35 AM
I have a grid called 'Incidents'. Now I want to show in a tab a grid with incidents with 'status' is new. I instantiate a incident grid to newincident and add a on('beforeload') to set baseParams to this newincident grid to filter records with status = new. So this newincident grid always shows only 'new' records. Is this the proper way to use baseParams or should I use params??

@pcr, rblon -- Follow along. Given:



var newIncidentStore = new Ext.data.Store({
baseParams : { status : 'new' }
});

newIncidentStore.load({ params : { injuries : 'yes' } });
//or
newIncidentStore.on('beforeload', function(store, options){
options.params.injuries = 'yes';
});
newIncidentStore.load();
Would yield a request with the following params: status = new & injuries = yes



newIncidentStore.setBaseParam('sex', 'female'); //new baseParam for all future requests
newIncidentStore.load({ params : { status : 'resolved' } });

Would yield a request with the following params: status = resolved & sex = female

and, a simple:


newIncidentStore.setBaseParam('sex', 'male'); // baseParam changed for all future requests
newIncidentStore.load();Would yield a request with the following params: status = new & sex = male

All thanks to what's going on under the covers:


options = Ext.applyIf(options||{}, { params: {}}); //assert params
Ext.applyIf(options.params, this.baseParams); //mixin, params wins any conflicts!
As you can see, there are several ways to handle static and dynamic param changes. :-?

mschwartz
23 Dec 2009, 12:48 PM
Maybe this is toooooo clever, but...

If params or baseParams are functions, you could call them. They'd return some object.

hendricd
23 Dec 2009, 12:50 PM
Yes, I forgot to add that option into the mix.

Nice grab. =D>

sunmoonone
25 Jan 2010, 5:29 PM
When call store.load and I do override(add or set) the baseParams of an instance of Ext.data.Stroe in the callback of the 'beforeload' event.
But new params I set can not be post to the server.
I checked the source code of 3.0 and 3.1.0 and found a big different procedure when overriding the options.params:
In 3.0:
new params is applied just before the request:


if (doRequest !== false) {
// Send request to proxy.
var params = Ext.apply({}, options.params, this.baseParams);

But in 3.1.0 the params is set too early, It is set even before firing the 'beforeload' event:


if (action === 'read') {
Ext.applyIf(options.params, this.baseParams);
doRequest = this.fireEvent('beforeload', this, options);
}

I think it is the very reason why new params set to store.baseParams can not be sent to the server.

sunmoonone
25 Jan 2010, 5:44 PM
In fact we can override the options.params used by the request (in execute function) without touching the baseParams in this way:


yourstore.on('beforeload',function(store,options){
var new_params={some_key:some_val};
Ext.apply(options.params,new_params);
});


and more:
I have a small function to watch the (attributes,values) of an object, when you debuging your code, it is very useful:


alertdir:function(obj){
if (obj && typeof obj == 'object'){
msg='{';
for (attr in obj){
msg+=attr+':'+obj[attr]+",";
}
if (msg.length>1)
msg=msg.slice(0,msg.length-1);

msg+='}'
alert(msg);
}else{alert(obj)}
}

mystix
26 Jan 2010, 4:17 AM
@sunmoonone: if you're reporting a new bug, i'd suggest starting a new thread, since this thread's already been marked [FIXED] and so may miss being monitored by the dev team for changes.

rblon
26 Jan 2010, 4:22 AM
this workaround had already been suggested


In fact we can override the options.params used by the request (in execute function) without touching the baseParams in this way:


yourstore.on('beforeload',function(store,options){
var new_params={some_key:some_val};
Ext.apply(options.params,new_params);
});



is the same as



It seems that when I change, in the beforeload event, every instance of


store.setBaseParam('foo', 'bar');

to


Ext.apply(options.params, {foo : 'bar'});

it works as "params will override any baseParams of the same name".

mschwartz
12 Feb 2010, 7:12 AM
Using a DataStore with JsonReader. On render, I call store.reload() and no parameters are posted to the server. I do have a beforeLoad listener that sets baseParams, but those aren't being sent.

I step into reload() and see that it is doing this:


20293 this.load(Ext.applyIf(options||{}, this.lastOptions));


Options is undefined and obviously this.lastOptions is {}

I am not seeing that baseParams is being honored at all.

This bug still occurs in Ext 3.1.1

ds.reload();

ds has a beforeload listener that modifies baseParams

those baseParams are overridden by lastOptions.

Jamie Avins
12 Feb 2010, 9:22 AM
A refactor for the data code is planned for the 3.2.x base to address many issues like this. This thread is already too difficult to follow to add new issues to it. Can you provide a complete test case in a new thread so we are sure to have it addressed.