PDA

View Full Version : Store or JsonWriter Ajax UPDATE buffer?



lzaiats
4 Jun 2009, 2:12 PM
Hi! I am having some weird experience trying to update some records using a Store (restful enabled) with a HttpProxy pointing to my backend REST url and a JsonWriter. Here´s the code:


Ext.each(this.deselected, function (item, index, all) {
item.set('selected', false);
}, this);

Ext.each(this.selected, function (item, index, all) {
item.set('selected', true);
}, this);Every array (this.selected and this.deseleceted) only have 1 single record inside, but when i execute this code my Firebug shows me 3 PUT requests, 2 for the same deselected record and 2 for the selected record.

Here is the full code:


Ext.onReady(function(){
Ext.ns('C0D1X');

C0D1X.user_record = Ext.data.Record.create([{
name: 'id_user'
}, {
name: 'username'
}, {
name: 'password'
}, {
name: 'email'
}, {
name: 'active'
}, {
name: 'groups'
}]);

C0D1X.user_group_record = Ext.data.Record.create([{
name: 'id_group'
}, {
name: 'name'
}, {
name: 'active'
}, {
name: 'selected'
}]);

Ext.Ajax.defaultHeaders = {
'Accept': 'application/json'
};

C0D1X.user_grid_window = function(config){
Ext.applyIf(this, config);

this.context_menu = new Ext.menu.Menu({
items: [{
text: 'Editar Registro',
scope: this,
handler: function(){
var user_record = this.grid.getSelectionModel().getSelected();
var user_form = new C0D1X.user_form().show();
user_form.loadRecord(user_record);
}
}, {
text: 'Editar Grupos',
scope: this,
handler: function(){
var user_record = this.grid.getSelectionModel().getSelected();
var user_group_grid_window = new C0D1X.user_group_grid_window().show();
user_group_grid_window.loadRecord(user_record);
}
}, {
text: 'Editar Telefones',
scope: this,
handler: function(){
/*var user_record = this.grid.getSelectionModel().getSelected();
var user_group_grid_window = new C0D1X.user_group_grid_window().show();
user_group_grid_window.loadRecord(user_record);*/
}
}]
});

this.grid = new Ext.grid.EditorGridPanel({
bodyBorder: false,
border: false,

autoExpandColumn: 'email',

columns: [new Ext.grid.RowNumberer(), {
header: 'id_user',
dataIndex: 'id_user',
hidden: true
}, {
header: 'Username',
dataIndex: 'username'
}, {
header: 'Password',
dataIndex: 'password',
renderer: function(){
return '********';
}
}, {
header: 'Email',
dataIndex: 'email',
id: 'email'
}, {
header: 'Active',
dataIndex: 'active'
}],

sm: new Ext.grid.RowSelectionModel(),

store: new Ext.data.Store({
id: 'user',
restful: true,

proxy: new Ext.data.HttpProxy({
url: 'http://192.168.0.61/projects/sm-migration/controlPanel/user'
}),

reader: new Ext.data.JsonReader({
successProperty: 'success',
idProperty: 'id_user',
root: 'data',
}, C0D1X.user_record),

writer: new Ext.data.JsonWriter({
returnJson: true
}),

listeners: {
exception: function(proxy, type, action, options, res, arg){
if (type === 'remote') {
Ext.Msg.show({
title: 'SERVER ERROR',
msg: res.message,
icon: Ext.MessageBox.ERROR
});
}
}
}
}),

listeners: {
'rowcontextmenu': {
scope: this,
fn: function(grid, index, e){
e.stopEvent();
var coords = e.getXY();
grid.getSelectionModel().selectRow(index);
this.context_menu.showAt([coords[0], coords[1]]);
}
}
}
});

C0D1X.user_grid_window.superclass.constructor.call(this, {
title: 'User Grid',
width: 640,
height: 480,

resizable: false,
draggable: false,
closable: false,

layout: 'fit',

items: [this.grid],

tbar: [{
text: '[add]',
scope: this,
handler: function(){
new C0D1X.user_form().show();
}
}, {
text: '[del]',
scope: this,
handler: function(){
}
}]
});

this.grid.store.load();
}
Ext.extend(C0D1X.user_grid_window, Ext.Window);

C0D1X.user_form = function(config){
Ext.applyIf(this, config);

this.update_form = false;
this.user_record = null;

this.loadRecord = function(record){
this.user_record = record;
this.user_form.getForm().loadRecord(this.user_record);
this.update_form = true;
}

this.user_form = new Ext.form.FormPanel({
layout: 'column',

trackResetOnLoad: true,
bodyStyle: 'padding: 10px;',
autoHeight: true,

labelAlign: 'top',

defaults: {
border: false,
bodyBorder: false
},

items: [{
layout: 'form',
columnWidth: 1,
items: [{
name: 'username',
xtype: 'textfield',
fieldLabel: 'Username',
allowBlank: false,
blankText: 'Campo obrigatório',
anchor: '100%'
}]
}, {
layout: 'form',
columnWidth: 1,
items: [{
name: 'password',
xtype: 'textfield',
inputType: 'password',
fieldLabel: 'Password',
allowBlank: false,
blankText: 'Campo obrigatório',
anchor: '100%'
}]
}, {
layout: 'form',
columnWidth: 1,
items: [{
name: 'email',
xtype: 'textfield',
fieldLabel: 'Email',
allowBlank: false,
blankText: 'Campo obrigatório',
anchor: '100%'
}]
}, {
layout: 'form',
columnWidth: 1,
items: [{
name: 'active',
xtype: 'checkbox',
inputValue: 1,
fieldLabel: 'Active',
allowBlank: false,
blankText: 'Campo obrigatório'
}]
}]

});

C0D1X.user_form.superclass.constructor.call(this, {
title: 'User Form',
width: 400,

resizable: false,
draggable: false,
closable: false,

layout: 'fit',

bodyBorder: false,
border: false,
modal: true,

buttons: [{
text: 'Salvar',
scope: this,
handler: function(){
if (this.update_form) {
this.user_form.getForm().updateRecord(this.user_record);
this.close();
}
else {
var raw_values = this.user_form.getForm().getValues();
var user_store = Ext.StoreMgr.get('user');
this.user_record = new user_store.recordType(raw_values);
user_store.insert(0, this.user_record);
this.close();
}
}
}, {
text: 'Limpar',
scope: this,
handler: function(){
this.user_form.getForm().reset();
}
}, {
text: 'Cancelar',
scope: this,
handler: function(){
this.close();
}
}],

items: [this.user_form]
});
}
Ext.extend(C0D1X.user_form, Ext.Window);

C0D1X.user_group_grid_window = function(config){
Ext.applyIf(this, config);

this.user_record = null;
this.selected = [];
this.deselected = [];

this.loadRecord = function(record){
this.user_record = record;
this.grid.store.proxy.setUrl(this.grid.store.proxy.url + '/' + this.user_record.get('id_user'), true);
this.grid.store.load();
}

this.sm = new Ext.grid.CheckboxSelectionModel({
checkOnly: true,

listeners: {
rowselect: {
scope: this,
fn: function(sm, index, record){
this.selected.push(record);
}
},

rowdeselect: {
scope: this,
fn: function(sm, index, record){
this.deselected.push(record);
}
}
}
});

this.grid = new Ext.grid.GridPanel({
bodyBorder: false,
border: false,

autoExpandColumn: 'name',

columns: [this.sm, {
header: 'id_group',
dataIndex: 'id_group',
hidden: true
}, {
header: 'Name',
id: 'name',
dataIndex: 'name'
}],

sm: this.sm,

store: new Ext.data.Store({
id: 'groups',
restful: true,

proxy: new Ext.data.HttpProxy({
url: 'http://192.168.0.61/projects/sm-migration/controlPanel/user/groups'
}),

reader: new Ext.data.JsonReader({
successProperty: 'success',
idProperty: 'id_group',
root: 'data',
}, C0D1X.user_group_record),

writer: new Ext.data.JsonWriter({
returnJson: true
}),

listeners: {
exception: {
scope: this,
fn: function(proxy, type, action, options, res, arg){
if (type === 'remote') {
Ext.Msg.show({
title: 'SERVER ERROR',
msg: res.message,
icon: Ext.MessageBox.ERROR
});
}
}
},

load: {
scope: this,
fn: function(store, records, options){
this.sm.selectRecords(records.filter(function(item){
return item.get('selected');
}));

this.selected = [];
this.deselected = [];
}
}
}
})
});

this.grid.getView().selectedRowClass += ' x-grid3-row-selected-checkbox';

C0D1X.user_group_grid_window.superclass.constructor.call(this, {
title: 'Group Grid',
width: 400,
height: 300,

resizable: false,
draggable: false,
closable: false,

modal: true,

layout: 'fit',

items: [this.grid],

buttons: [{
text: 'Salvar',
scope: this,
handler: function(){
Ext.each(this.deselected, function(item, index, all){
item.set('selected', false);
}, this);

Ext.each(this.selected, function(item, index, all){
item.set('selected', true);
}, this);

this.close();
}
}, {
text: 'Cancelar',
scope: this,
handler: function(){
this.close();
}
}]
});
}
Ext.extend(C0D1X.user_group_grid_window, Ext.Window);

new C0D1X.user_grid_window().show();
});
Here´s the Firebug log:

PUT http://192.168.0.61/projects/sm-migration/controlPanel/user/groups/23/2
PUT http://192.168.0.61/projects/sm-migration/controlPanel/user/groups/23/2
PUT http://192.168.0.61/projects/sm-migration/controlPanel/user/groups/23/1

Any idea?

watrboy00
6 Jun 2009, 12:47 PM
I am having the same issue and it came with the latest upgrade to RC2.

It seems that the logic is a little off...



batch (http://extjs.com/deploy/ext-3.0-rc2/docs/source/Store.html#cfg-Ext.data.Store-batch) : Boolean
Defaults to true (unless restful (http://extjs.com/deploy/ext-3.0-rc2/docs/output/Ext.data.Store.html#Ext.data.Store-restful):true). Multiple requests for each CRUD action (CREATE, READ, UPDATE and DESTROY) will be combined and sent as one transaction. Only applies when autoSave (http://extjs.com/deploy/ext-3.0-rc2/docs/output/Ext.data.Store.html#Ext.data.Store-autoSave) is set to false.

If Store is RESTful, the DataProxy is also RESTful, and a unique transaction is generated for each record.



So basically you will have a unique transaction generated for each record using the restful config options which is a good thing. However, what actually happens is a unique transaction is created for any field change on the record...not just one for the record.

watrboy00
6 Jun 2009, 1:30 PM
Posted a bug report...

https://extjs.com/forum/showthread.php?p=339397#post339397

lzaiats
6 Jun 2009, 1:53 PM
Perfect! Every time i set a field, like my_record.set('name', 'my_new_name'), a new transaction is created and submitted...

Other problem i found is when trying to use setUrl() from HttpProxy when restful = true in my Store...

I needed to change this code:


prepare : function(proxy) {
if (!proxy.api) {
proxy.api = {}; // <-- No api? create a blank one.
}
for (var verb in this.actions) {
var action = this.actions[verb];
proxy.api[action] = proxy.api[action] || proxy.url || proxy.directFn;
if (typeof(proxy.api[action]) == 'string') {
proxy.api[action] = {
url: proxy.api[action]
};
}
}
}
to this:



prepare : function(proxy) {
if (!proxy.api) {
proxy.api = {}; // <-- No api? create a blank one.
}
for (var verb in this.actions) {
var action = this.actions[verb];
proxy.api[action] = proxy.api[action] || proxy.url || proxy.directFn;
// This IF is mine (dont know the size of impact)
if(proxy.api[action].url && proxy.url) {
// If i am using api actions, i need to set the url for this action, or i will not get the expected result...
proxy.api[action].url = proxy.url;
}
if (typeof(proxy.api[action]) == 'string') {
proxy.api[action] = {
url: proxy.api[action]
};
}
}
}