PDA

View Full Version : [FIXED][3.0rc1] cannot use onCreateRecord event to update pk



iwtlf
29 Apr 2009, 8:46 PM
Hi,

I need to add a record to a store and then [mostly] automatically update my pk based on the one generated by the server.

It seems to me that this is what onCreateRecord is for but I haven't seen it documented anywhere so I'm not entirely certain what I'm doing wrong here. I'm not calling it directly as it is called automatically when I save the changes to the store. Here's the code:



var usersStore = new Ext.data.Store({
url: 'users',
reader: new Ext.data.JsonReader({
root: 'users',
successProperty: 'success',
id: 'key',
fields: [
{name: 'key'},
{name: 'nickname'}
]
}),
writer: new Ext.data.JsonWriter({writeAllFields:true}),
sortInfo:{field:'nickname', direction:'ASC'},
batchSave: true,
remoteSort: false
});

var userRecord = Ext.data.Record.create(['key','nickname']);

var nRec = new userRecord({
nickname: 'test'
});
usersStore.add(nRec);
usersStore.save(nRec);


This part works fine and does send what I need to the server, which in turn does create the new record in the DB and assigns it an ID. Now I then output the following as the response (note: I have no idea what it is expecting so this was my best guess):



{"data": {"key": "somestring"}, "success": true}


And this is what firebug gives me:



this.reader.meta.idProperty is undefined
DomHelper()(Object phantom=true id=ext-record-1 data=Object, undefined)ext-all.js (line 1)
DomHelper()(undefined, Object data=Object success=true, true)ext-all.js (line 1)
DomHelper()(Object params=Object request=Object reader=Object, true, Object tId=3 status=200 statusText=OK)ext-all.js (line 1)
b(Object tId=3 status=200 statusText=OK)ext-all.js (line 1)
handleTransactionResponse()ext-base.js (line 104)
handleReadyState()()ext-base.js (line 112)
[Break on this error] Ext.DomHelper=function(){var w=null,l=/^...(Ext.History,new Ext.util.Observable());


Any help will be appreciated :) thanks

Animal
30 Apr 2009, 4:30 AM
Don't you think the Store has a Record definition? Something it possibly derives from the fields config? See the API docs.

Also, use idProperty instead of id

http://extjs.com/playpen/docs/?class=Ext.data.JsonReader&member=idProperty

But also, you have to tell it its ID when you create it! http://extjs.com/playpen/docs/?class=Ext.data.Record&member=Record

mschwartz
30 Apr 2009, 5:27 AM
But also, you have to tell it its ID when you create it! http://extjs.com/playpen/docs/?class=Ext.data.Record&member=Record

Thanks for the link. Makes me want to upgrade to Ext 1.1 beta 2 now :)

iwtlf
30 Apr 2009, 6:00 AM
Thanks for the reply.

I still don't fully get it though... I changed the code to that, which does work better:



var userRecord = Ext.data.Record.create(['nickname']);
var usersStore = new Ext.data.Store({
url: 'users',
reader: new Ext.data.JsonReader({
root: 'users',
successProperty: 'success',
idProperty: 'key'
}),
writer: new Ext.data.JsonWriter({writeAllFields:true}),
sortInfo:{field:'nickname', direction:'ASC'},
batchSave: true,
remoteSort: false
},userRecord);

var nRec = new userRecord({
nickname: 'test'
});
usersStore.add(nRec);
usersStore.save(nRec);


I then return (I had already tried that format btw, but my propertyId was not set at the time):


{"users": [{"key": "somestring"}], "success": true}


It now works fine except that it doesn't update the record's PK (and, logically so, keeps it dirty).


But also, you have to tell it its ID when you create it!

I'm not sure I understand that part though. If I do specify the ID when I create the record then it isn't marked as being phantom anymore and won't be sent to the server. Also, when I don't specify it, Ext will create a temporary unique key for me all the while marking the record as phantom, which is precisely the behavior I would expect pending a server update.
When the server sends the data back with the actual PK, the onCreateRecord function does still have a reference to the record, and I would expect it to consume the JSON to update it and set the key.
Is the returned JSON incorrectly formatted? What else am I misunderstanding here?

Thanks.

mjlecomte
30 Apr 2009, 7:29 AM
I'd set a breakpoint at this line and debug:


realize: function(rs, data){
...
var values = this.extractValues(data, rs.fields.items, rs.fields.items.length);

iwtlf
30 Apr 2009, 8:19 AM
Ok so just to bring closure to this post.. this is the expected JSON string:

{"users": {"key": "somestring"}, "success": true}

The thing that through me off is that I didn't know the reader could deal with something other than an array of objects in the root property, combined with the fact that when you create the record it expects just one object (directly) and will not accept an array of one.

mjlecomte
30 Apr 2009, 9:09 AM
I don't know if my pointer is the one that tipped you off or not, but if you did break in that area I believe it "should" handle an array, and if it does not, it "might" be a bug. If you debug with the original source files you can see the commentary that seems to indicate it should process an array.

mjlecomte
30 Apr 2009, 9:29 AM
Looks like it may expect the type of the data returned to match the type sent out. So if you create one record, you need to send one record back. If you create multiple records, then you'd send an array back.

This area of the code has been evolving. Maybe the data type will be standardized/fixed to just take an array to simplify things.

christocracy
30 Apr 2009, 10:16 AM
For the actions "create", "destroy" and "save", the response data must be of the same form as the request.

If you create, destroy or save 1 record, send 1 record back.
If you create, destroy or save x records, send x records back in an array.

Further, when receiving x records to create, destroy or save, the records must be returned in the same order received (currently).

However, I'm sure I can re-tool the DataReader to pick out the single record if you send back an Array of 1 record.

iwtlf
30 Apr 2009, 10:29 AM
[to mjlecompte] I'd looked at the code but not debugged it since it originally didn't get into the function at all (I had the wrong meta id property set). Your post prompted me to spend more time with the debugger now that the other issue was fixed.

[to christocracy] I think it'll be useful to expand a bit on the documentation in this regard.

christocracy
30 Apr 2009, 11:47 AM
I've modified DataReader#realize, DataReader#update to accept Array from server when saving/creating single records.

committed to SVN.



// If rs is NOT an array but data IS, see if data contains just 1 record. If so extract it and carry on.
if (Ext.isArray(data) && data.length == 1) {
data = data.shift();
}

iwtlf
2 May 2009, 7:13 PM
Nice. Thanks.

I have another problem though... I already have 2 objects in the store and then add a new one with the code I detailed in that post (with all the corrections).

Here's what I get in firebug though:

>>> App.usersStore.getAt(0)
Object id=somekey1
>>> App.usersStore.getAt(1)
Object id=somekey2
>>> App.usersStore.getAt(2)
Object phantom=false

Now the third record does have an id (set automatically to the server's pk). Somehow it is treated differently from the other records. It doesn't seem to affect it in any way except that its selection/deselection in a grid based on that store doesn't work well.

Basically once selected, I can select another record but the third one will not visually be deselecedt unless I Ctrl-click it.

If I destroy the grid and recreate it then the problem will go away and the output in firebug becomes the expected:

>>> App.usersStore.getAt(0)
Object id= somekey1
>>> App.usersStore.getAt(1)
Object id= somekey2
>>> App.usersStore.getAt(2)
Object id= somekey3

Here's the code for the grid:

var selM = new Ext.grid.RowSelectionModel({
singleSelect:true,
listeners:{
selectionchange: function(sm){
if(sm.getCount()==1&&sm.getSelected().id!=App.user.id){
// something
} else{
// something
}
}
}
});
var grid = new Ext.grid.GridPanel({
stateId:'app_g_users',
store:usersStore,
border:true,
loadMask:true,
stripeRows:true,
viewConfig:{forceFit:true},
selModel:selM,
cm:new Ext.grid.ColumnModel([
{header: "Nickname", width: 100, sortable: true, dataIndex: 'nickname'}
]),
listeners:{
rowdblclick: function(){
// do something
}
}]
});

Note: the problem only occurs after I have called the save method on the store and it sets the id based on the returned PK. There is no issue with a newly added record per se.

For instance, this code alone will be fine:

var nRec = new userRecord({
nickname: "Test"
});
usersStore.addSorted(nRec);

The selections will work as expected until I call the store's save() function and it updates the added record with the server's PK.

christocracy
2 May 2009, 7:24 PM
Roger, I'm on it.

iwtlf
3 May 2009, 8:11 PM
Also, doing the following does not return anything for a newly created record even though the key has been set and can be accessed with the id property of the record (all other records are returned just fine):

usersStore.getById('newPKasReturnedByServer')

Only way to make it work is to reload the store.

iwtlf
4 May 2009, 6:45 AM
Still broken as of RC1.1 (I made the necessary changes to the code to reflect the revamped CRUD functions - the record has its ID set just fine).

Note: to go around it, I use the following (temporarily hopefully):

usersStore.getAt(usersStore.find('key','newPKasReturnedByServer'))

christocracy
11 May 2009, 2:08 PM
Ok, she's good-to-go in SVN. Newly realized records are now re-mapped in Store's underlying MixedCollection. Big thanks to Mr LeCompte (http://extjs.com/forum/member.php?u=6834) for keeping me informed and delivering to me the solution code on a platter prepared by Mr Condor (http://extjs.com/forum/member.php?find=lastposter&t=68142).