i'm trying to make that a combo load the items (dataStore) with AutoLoad: true, but, i don't know if i'm doing this right. I'm a little newbie with Extjs, so, don't be rude, please hehe
here's the code!
items: [{
xtype: 'form',
padding: 20,
name: 'formReplyParameters',
layout: 'anchor',
fieldDefaults: {
msgTarget: 'under',
labelAlign: 'top'
},
defaults: {
padding: 10
},
items: [{
xtype: 'checkboxfield',
name: 'interactive',
inputValue: true,
fieldLabel: 'Interactive',
anchor: '100%'
}, {
xtype: 'textfield',
name: 'timeResponse',
fieldLabel: 'Time response',
anchor: '100%'
}, {
xtype: 'combobox',
fieldLabel: 'Alert channel',
name: 'uuidResponseParameterType',
queryMode: 'local',
store: new Ext.data.Store({
fields: [{
name: 'description',
type: 'string'
}, {
name: 'name',
type: 'string'
}, {
name: 'uuid',
type: 'string'
}],
autoLoad: true,
hideTrigger: true,
minChars: 1,
triggerAction: 'query',
typeAhead: true,
proxy: {
type: 'ajax',
url: "../blabla",
actionMethods: {
create: "POST",
read: "POST",
update: "POST",
destroy: "POST"
},
extraParams: {
action: "catalog",
catalog: "parametersType",
params: JSON.stringify({
uuidToken: Ext.connectionToken
})
},
reader: {
type: 'json',
root: 'List'
},
listeners: {
exception: function(proxy, response, operation, eOpts) {
var responseArray = JSON.parse(response.responseText);
Ext.Notify.msg(responseArray.message, {
layout: "bottomright",
delay: 5000,
type: "error"
});
}
}
}
}),
anchor: '100%',
typeAhead: true,
triggerAction: 'all',
valueField: 'uuid',
displayField: 'description',
allowBlank: false,
listeners: {
change: function (combo, value) {
var type = combo.valueModels[0].data.name;
var channel = me.down('[name="uuidChanel"]');
channel.clearValue();
var channelStore = new Ext.data.Store({
fields: [{
name: 'description',
type: 'string'
}, {
name: 'name',
type: 'string'
}, {
name: 'uuid',
type: 'string'
}],
autoLoad: true,
hideTrigger: true,
minChars: 1,
triggerAction: 'query',
typeAhead: true,
proxy: {
type: 'ajax',
url: "../handler/custom/customEvent.ashx",
extraParams: {
action: "catalog",
catalog: type,
params: JSON.stringify({
uuidToken: Ext.connectionToken
})
},
reader: {
type: 'json',
root: 'list'
},
listeners: {
exception: function(proxy, response, operation, eOpts) {
var responseArray = JSON.parse(response.responseText);
Ext.Notify.msg(responseArray.message, {
layout: "bottomright",
delay: 5000,
type: "error"
});
}
}
}
});
channelStore.load();
channel.bindStore(channelStore);
}
}
}, {
xtype: 'combo',
name: 'uuidChanel',
fieldLabel: 'Channel',
valueField: 'uuid',
displayField: 'description',
anchor: '100%',
store: null,
allowBlank: false
}]
}]
The problem is in the combo: uuidChannel
if anyone can help, thanks a lot!
Why exactly you think that autoLoad: true doest work? Because when you try to open last combobox picker its still loading?
I think your problem is that new store created every time combo name: 'uuidResponseParameterType' change event trigger and store autoLoad: true means that
store's load method is automatically called after creation
You have to create store just once and load (or filter locally) it with new extraParams on combo change event.
The thing is that (stupid)
channel.clearValue();
this field was doing all the problem. this "clearValue" was there because I believed that deleting the data of "uuid", it was returning me the new data with the "bind" to the bottom
channelStore.load();
channel.bindStore(channelStore); <<<
So, I think i put the new data, but this "clearValue", just was erasing the data with the "bind" I had down. So, i just elimite that channel.clearValue(); , and that's solves the problem! :)
Related
I'm unsuccessful in getting binding associations working in the admin dashboard template (with the desired behavior of selecting a record from a combobox and pulling up associated records in a grid).
My main viewModel is defined as:
Ext.define('Admin.view.main.MainModel', {
extend: 'Ext.app.ViewModel',
alias: 'viewmodel.main',
stores: {
patients: {
model: 'md_registry.model.Patient',
autoLoad: true
}
}
});
I added a leaf node to Pages in NavigationTree.js:
{
text: 'Pages',
iconCls: 'x-fa fa-leanpub',
expanded: false,
selectable: false,
//routeId: 'pages-parent',
//id: 'pages-parent',
children: [
{
text: 'Proc',
iconCls: 'x-fa fa-send',
rowCls: 'nav-tree-badge nav-tree-badge-hot',
viewType: 'procedure',
leaf: true
}]
}
With the procedure view being:
Ext.define('Admin.view.pages.Procedure', {
extend: 'Ext.panel.Panel',
xtype: 'procedure',
requires: [
'Ext.panel.Panel',
'Admin.model.Patient',
'Admin.model.Procedure'
//'Admin.model.Diagnosis'
],
anchor : '100% -1',
referenceHolder: true,
width: 1000,
height: 1000,
referenceHolder: true,
layout: {
type: 'hbox',
align: 'stretch'
},
viewModel: 'main',
session: {},
items: [
// https://www.sencha.com/forum/showthread.php?299301-Bind-combobox-displayField-value-to-displayfield
{
xtype: 'fieldset',
layout: 'anchor',
items: [{
xtype: 'combobox',
listeners : {
select : function() {
console.log(arguments)
console.log(arguments[1].data.birth_date)
console.log(arguments[1].data.first_name)
console.log(arguments[1].data.last_name)
console.log(arguments[1].data.sex)
}
},
bind: {
store: '{patients}'
},
reference: 'patientCombo',
publishes: 'id',
fieldLabel: 'Patient Search',
displayField: 'mrn',
//anchor: '-',
// We're forcing the query to run every time by setting minChars to 0
// (default is 4)
minChars: 2,
queryParam: '0',
queryMode: 'local',
typeAhead: true,
// https://www.sencha.com/forum/showthread.php?156505-Local-combobox-with-any-match-filter
doQuery: function(queryString, forceAll) {
this.expand();
this.store.clearFilter(!forceAll);
if (!forceAll) {
this.store.filter(this.displayField, new RegExp(Ext.String.escapeRegex(queryString), 'i'));
}
}
}, {
// https://www.sencha.com/forum/showthread.php?299301-Bind-combobox-displayField-value-to-displayfield
xtype: 'displayfield',
fieldLabel: 'Selected Patient',
bind: {
html: '<p>Name: <b>{patientCombo.selection.first_name}, ' +
'{patientCombo.selection.last_name} </b></p>' +
'<p>Sex: {patientCombo.selection.sex}</p>' +
'<p>Birthdate: {patientCombo.selection.birth_date}</p>'
}
}]
},
{
title: 'Procedures',
xtype: 'grid',
bind: '{patientCombo.selection.procedures}',
flex: 1,
margin: '0 0 0 10',
columns: [{
text: 'Procedure Date', dataIndex: 'proc_date', flex: 1
}, {
text: 'Procedure', dataIndex: 'proc_name', flex: 1
}],
plugins: [{
ptype: 'rowexpander',
rowBodyTpl : new Ext.XTemplate(
'<p><b>Proc Name Orig:</b> {proc_name_orig}</p>',
'<p><b>Proc Code:</b> {proc_code}</p>',
'<p><b>Proc Code Type:</b> {proc_code_type}</p>')
}],
viewConfig: {
emptyText: 'No procedures',
deferEmptyText: false
}
}]
});
My Patient and Procedure models are simply:
Ext.define('Admin.model.Procedure', {
extend: 'Ext.data.Model',
idProperty: 'id',
fields: [
//{ name: 'id', type: 'string' },
{ name: 'proc_code', type: 'string' },
{ name: 'proc_name', type: 'string' },
{ name: 'proc_code_type', type: 'string' },
{ name: 'proc_name_orig', type: 'string' },
{ name: 'proc_date', type: 'date', format: 'Y-m-d' },
{
name: 'patient_id',
type: 'string',
reference: {
parent: 'Admin.model.Patient',
//type: 'md_registry.model.Patient',
inverse: 'procedures',
autoLoad: false
}
}
],
proxy: {
type: 'rest',
url: 'http://127.0.0.1:5000/procedureview/api/read',
reader: {
type: 'json',
rootProperty: ''
}
}
});
and
Ext.define('Admin.model.Patient', {
extend: 'Ext.data.Model',
requires: [
'Ext.data.proxy.Rest'
],
fields: [
{ name: 'id', type: 'string' },
{ name: 'mrn', type: 'string' },
{ name: 'birth_date', type: 'date', format: 'Y-m-d' },
{ name: 'sex', type: 'string' },
{ name: 'first_name', type: 'string' },
{ name: 'last_name', type: 'string' }
],
proxy: {
type: 'ajax',
url: 'http://127.0.0.1:5000/patientview/api/read',
reader: {
type: 'json',
rootProperty: ''
}
}
});
respectively.
The data for my Patients store are getting loaded into the combobox just fine, but when I select an item from the combo list it is not firing off the call to grab the associated procedures data (see image: .
However, the binding associations work as expected with Side Navigation Tabs (see image: , and show up within the object prototype chain, as expected... see
(whereas for the admin dashboard, the associations are empty).
I cannot for the life of me get these working in the Admin Dashboard. I noticed a tool called the bind inspector, but I am running the GPL version of the SDK, so I do not have access to this. Beyond this, I cannot figure out a way to debug why the binding association is not working in the admin dashboard, but otherwise works perfectly well in Side Navigation Tabs.
I would set up a Fiddle, but I have no idea how to do it using the Admin Template.
I just figured it out. It was a namespace issue.
My reference in the procedure model should be:
reference: {
parent: 'Patient',
inverse: 'procedures',
autoLoad: false
}
Voila, all the associated data get loaded as expected!
I am trying to convert some ExtJS 3.3 to 4.0.
In ExtJS 3.x I could create a combobox with a unique component Id, that I could use later with Ext.getCmp(Id), to get that combo editor, so that I could add filters, or play with the combo box itself.
Now if I specify an Id, the grid does not render the combo box correct in the grid, they say I have to use itemId instead, then actually it works, I mean combo renders correctly on the grid, But then I have no way of using that itemId to get the combobox itself.
I tried grid.getComponent(itemId), grid.headerCt.getComponent(), I have to say what the heck is this itemId good for, how on earth am I supposed to get this editor.
grid.columns collection has editor for simple fields (like text, number), for combobox it has getEditor which asks for a data record as a param.
I have to say again wtf, was so wrong with ExtJS 3.x that they felt like fixing and f.... it up.
Really, this upgrade made me go wtf so many times.... maybe its my fault, but wtf... anyways.
{
header: 'Ürün/Hizmet',
width: 90,
dataIndex: 'AlinanHizmetId',
editor: {
itemId: 'AlinanHizmetId',
xtype: 'combobox',
allowBlank: false,
selectOnFocus: true,
valueField: 'Id',
displayField: 'HizmetAd',
triggerAction: 'all',
typeAhead: false,
forceSelection: true,
lazyRender: true,
minChars: '2',
listWidth: 300,
store: Ext.create('Ext.data.Store', {
storeId: '',
fields: [{
name: 'HizmetTipAd',
caption: 'Hizmet Tip Adı',
type: Ext.data.Types.STRING,
clrType: 'String'
}, {
name: 'Id',
caption: 'Id',
type: Ext.data.Types.STRING,
clrType: 'Guid'
}, {
name: 'HizmetTip',
caption: 'HizmetTip',
type: Ext.data.Types.STRING,
clrType: 'String'
}, {
name: 'HizmetKod',
caption: 'Hizmet Kodu',
type: Ext.data.Types.STRING,
clrType: 'String'
}, {
name: 'HizmetAd',
caption: 'Hizmet Adı',
type: Ext.data.Types.STRING,
clrType: 'String'
}, {
name: 'Aciklama',
caption: 'Açıklama',
type: Ext.data.Types.STRING,
clrType: 'String'
}],
autoDestroy: false,
autoLoad: true,
autoSave: false,
sortInfo: {
field: 'HizmetAd',
direction: 'ASC'
},
restful: false,
proxy: {
type: 'ajax',
actionMethods: {
read: 'POST'
},
url: '/Yol/Combo/AlinanHizmet',
reader: {
type: 'json',
root: 'data',
idProperty: 'Id',
totalProperty: 'rowCount',
successProperty: 'success',
messageProperty: 'message'
}
},
data: []
})
},
filter: {
xtype: 'textfield'
},
renderer: function (value, metaData, record, rowIndex, colIndex, store) {
return record.get('HizmetAd');
}
}
This is old - but have you tried grid.down('#item_id')?
mygrid.on('beforeedit', function(e){
if(e.field == 'ProductId') {
var gridCols = Ext.getCmp('my_grid').columns;
for(i = 0; i < gridCols.length; i++)
if (gridCols[i].dataIndex == 'ProductId') break;
var combo = gridCols[i].getEditor(e.record);
...
so actually column.getEditor(null) does the trick.
I'm trying to load a form from a record selected in a combo.
The store is loaded properly and the combo is populated, but, when I select a value from combo, form fields remain empty.
Any help will be appreciated.
This is the code:
Model:
Ext.define('AA.model.proc.Process', {
extend: 'Ext.data.Model',
fields: [
{ name: 'name', type: 'string' },
{ name: 'owner', type: 'string' },
{ name: 'mail_dest', type: 'string' }
],
proxy: {
type: 'rest',
url : 'data/camp.json',
reader: {
type: 'json',
root: 'camp',
totalProperty: 'count'
}
}
});
Store:
Ext.define('AA.store.proc.Process', {
extend: 'Ext.data.Store',
model: 'AA.model.proc.Process',
requires: 'AA.model.proc.Process'
});
Class:
Ext.define('AA.view.proc.IM', {
extend: 'Ext.window.Window',
alias: 'widget.im',
title: 'IM',
layout: 'fit',
height: 500,
width: 400,
autoShow: true,
plain: true,
modal: true,
headerPosition: 'right',
closable: false,
initComponent: function () {
this.items = [{
xtype: 'form',
fileUpload: true,
width: 550,
autoHeight: true,
border: false,
bodyStyle: 'padding:5px 5px 0',
frame: true,
labelWidth: 100,
defaults: {
anchor: '95%',
allowBlank: false,
msgTarget: 'side'
},
items: [{
xtype: 'combo',
name: 'name',
store: 'procstore',
fieldLabel: 'Name',
valueField: 'name',
displayField: 'name',
width: 150,
allowBlank: true,
listeners: {
scope: this,
'select': this.loadForm
}
}, {
xtype: 'textfield',
fieldLabel: 'Name',
name: 'name'
}, {
xtype: 'textfield',
fieldLabel: 'Owner',
name: 'owner'
}, {
xtype: 'textfield',
fieldLabel: 'E-mail owner',
name: 'mail_dest'
}]
}];
this.buttons = [{
text: 'Save',
action: 'save'
}, {
text: 'Cancel',
scope: this,
handler: this.close
}];
this.callParent(arguments);
},
loadForm: function (field, record, option) {
console.log(record)
// firebug returns
// $className "AA.model.proc.Process"
// $alternateClassName "Ext.data.Record"
console.log(this.down('form'))
// firebug returns the right form panel
this.down('form').loadRecord(record);
}
});
This is from the documentation for the select event:
select( Ext.form.field.ComboBox combo, Array records, Object eOpts )
Notice that the second parameter is an Array. But in your example the second parameter is an Ext.data.Record. You are treating array as a record. Modify your loadForm to make it process arrays of records:
loadForm: function (field,records,option) {
this.down('form').loadRecord(records[0]);
}
P.S. By the way you have two fields with name: 'name'.
I'm getting an error when selecting cells in my EditorGridPanel. Here's a snippet of my code:
var bannerGrid = new Ext.grid.EditorGridPanel({
store: bannerStore,
cm: new Ext.grid.ColumnModel({
defaults: {
sortable: true,
menuDisabled: true
},
columns:
{
header: '<img src="img/oo-icon.png" /> <img src="img/network-icon.png" />',
width: 52,
dataIndex: 'inventory',
align: 'center',
renderer: inventoryIcon,
}, {
header: "Name",
dataIndex: 'bannerName',
editor: new Ext.form.TextField({ allowBlank: false }),
width: 300
}, {
header: "Advertiser",
dataIndex: 'advertiser',
editor: advertisersDropdownGrid,
}, {
header: "Art Type",
dataIndex: 'artType',
editor: artTypeDropdownGrid,
}, {
......
Each of the 'editors' are dropdowns that are defined prior to the grid. The weird thing is that the editor that contains the TextField does not throw the same error.
The error I'm getting when selecting a cell is this:
c.getItemCt() is undefined
[Break On This Error] c.getItemCt().removeClass('x-hide-' + c.hideMode);
Again, this only happens on the ComboBox editors!
From further inspection the error is coming from this part of ext itself:
onFieldShow: function(c){
c.getItemCt().removeClass('x-hide-' + c.hideMode);
if (c.isComposite) {
c.doLayout();
}
},
Which seems to be part of the FormLayout section.
Any ideas? I've tried defining the Combo's inline and that did not fix it.
Thanks!
EDIT: Here's how I define my Combo's using classes.
I define my ComboBoxJSON class: (I've blanked out namespaces just for privacy sake)
***.***.***.ComboBoxJSON = Ext.extend(Ext.form.ComboBox, {
url: '',
root: '',
valueField: 'id',
displayField: 'name',
width: 200,
id: '',
fields: [
{ name: 'id', type: 'int'},
{ name: 'name', type: 'string' }
],
initComponent: function () {
var comboStore = new Ext.data.JsonStore({
id: 'JsonStore',
idProperty: 'id',
autoLoad: true,
idProperty: 'id',
root: this.root,
fields: this.fields,
proxy: new Ext.data.ScriptTagProxy({
api: {
read: this.url,
}
})
});
var config = {
store: comboStore,
displayField: this.displayField,
valueField: this.valueField,
mode: 'local',
minChars: 1,
triggerAction: 'all',
typeAhead: true,
lazyRender: true,
value: this.value,
width: this.width,
id: this.id
}
Ext.apply(this, config);
***.***.***.ComboBoxJSON.superclass.initComponent(this);
}
});
Ext.reg("ibwComboJson", ***.***.***.ComboBoxJSON);
I then define my combos before init on the grid, like so: (I've blocked out the URL, but it does return valid JSON)
var advertisersDropdownGrid = new ***.***.***.ComboBoxJSON({
url: '***',
root: 'advertiserList',
id: 'advertisersDropdownGrid'
});
Found the answer to this awhile back, but the solution is pretty absurdly simple.
***.***.***.ComboBoxJSON.superclass.initComponent.call(this);
Forgot the .call portion. :)
In my ExtJS application I use EditorGridPanel to show data from server.
var applicationsGrid = new Ext.grid.EditorGridPanel({
region: 'west',
layout: 'fit',
title: '<img src="../../Content/img/app.png" /> Приложения',
collapsible: true,
margins: '0 0 5 5',
split: true,
width: '30%',
listeners: { 'viewready': { fn: function() { applicationsGridStatusBar.setText('Приложений: ' + applicationsStore.getTotalCount()); } } },
store: applicationsStore,
loadMask: { msg: 'Загрузка...' },
sm: new Ext.grid.RowSelectionModel({
singleSelect: true,
listeners: { 'rowselect': { fn: applicationsGrid_onRowSelect} }
}),
viewConfig: { forceFit: true },
tbar: [{
icon: '../../Content/img/add.gif',
text: 'Добавить'
}, '-', {
icon: '../../Content/img/delete.gif',
text: 'Удалить'
}, '-'],
bbar: applicationsGridStatusBar,
columns: [{
header: 'Приложения',
dataIndex: 'ApplicationName',
tooltip: 'Наименование приложения',
sortable: true,
editor: {
xtype: 'textfield',
allowBlank: false
}
}, {
header: '<img src="../../Content/img/user.png" />',
dataIndex: 'UsersCount',
align: 'center',
fixed: true,
width: 50,
tooltip: 'Количество пользователей приложения',
sortable: true
}, {
header: '<img src="../../Content/img/role.gif" />',
dataIndex: 'RolesCount',
align: 'center',
fixed: true,
width: 50,
tooltip: 'Количество ролей приложения',
sortable: true}]
});
When I use JsonStore without reader it works, but when I try to update any field it uses my 'create' url instead of 'update'.
var applicationsStore = new Ext.data.JsonStore({
root: 'applications',
totalProperty: 'total',
idProperty: 'ApplicationId',
messageProperty: 'message',
fields: [{ name: 'ApplicationId' }, { name: 'ApplicationName', allowBlank: false }, { name: 'UsersCount', allowBlank: false }, { name: 'RolesCount', allowBlank: false}],
id: 'app1234',
proxy: new Ext.data.HttpProxy({
api: {
create: '/api/applications/getapplicationslist1',
read: '/api/applications/getapplicationslist',
update: '/api/applications/getapplicationslist2',
destroy: '/api/applications/getapplicationslist3'
}
}),
autoSave: true,
autoLoad: true,
writer: new Ext.data.JsonWriter({
encode: false,
listful: false,
writeAllFields: false
})
});
I believe that the problem is that I don't use reader, but when I use JsonReader grid stops showing any data at all.
var applicationReader = new Ext.data.JsonReader({
root: 'applications',
totalProperty: 'total',
idProperty: 'ApplicationId',
messageProperty: 'message',
fields: [{ name: 'ApplicationId' }, { name: 'ApplicationName', allowBlank: false }, { name: 'UsersCount', allowBlank: false }, { name: 'RolesCount', allowBlank: false}]
});
var applicationsStore = new Ext.data.JsonStore({
id: 'app1234',
proxy: new Ext.data.HttpProxy({
api: {
create: '/api/applications/getapplicationslist1',
read: '/api/applications/getapplicationslist',
update: '/api/applications/getapplicationslist2',
destroy: '/api/applications/getapplicationslist3'
}
}),
reader: applicationReader,
autoSave: true,
autoLoad: true,
writer: new Ext.data.JsonWriter({
encode: false,
listful: false,
writeAllFields: false
})
});
So, does anyone know what the problem might be and how to solve it. The data returned from my server is Json-formated and seams to be ok
{"message":"test","total":2,"applications":[{"ApplicationId":"f82dc920-17e7-45b5-98ab-03416fdf52b2","ApplicationName":"Archivist","UsersCount":6,"RolesCount":3},{"ApplicationId":"054e2e78-e15f-4609-a9b2-81c04aa570c8","ApplicationName":"Test","UsersCount":1,"RolesCount":0}]}
I had the same problem.. I solved it establishing Success Property in the json store and returning success true in the response from my create Method.. here is my code. Hope it helps
var EStore = new Ext.data.JsonStore
({
api: { read: 'getAssignedJobs',
create: 'createAssignedJobs',
update: 'updateAssignedJobs',
destroy: 'destroyAssignedJobs'},
root: 'jobData',
idProperty: 'Id',
autoSave: false,
autoLoad: true,
batch: true,
successProperty: 'success',
writer: new Ext.data.JsonWriter({ encode: true, writeAllFields: true }),
fields: [
{ name: 'Id', type: 'int', mapping: 'Id' },
{ name: 'ResourceId', type: 'int', mapping: 'fitter_id' },
{ name: 'StartDate', type: 'date', dateFormat: "Y-m-d\\TH:i:s" },
{ name: 'EndDate', type: 'date', dateFormat: "Y-m-d\\TH:i:s" },
{ name: 'status', type: 'int' },
{ name: 'job_id', type: 'int' }
]
});
and this is my Create method from Server Side..
public JsonResult createAssignedJobs(string jobData)
{
var Jsondata = (JobfitterToScheduler)new JavaScriptSerializer().Deserialize<JobfitterToScheduler>(jobData);
JobToFitterRepo jobtofitter = new JobToFitterRepo();
if (Jsondata != null)
{
jobtofitter.insertJobToFitter(13, Jsondata.fitter_id, 0, DateTime.Now, DateTime.Now);
return this.Json(new { success = true, jobData = Jsondata });
}
return null;
}
Looking at the source for Ext.data.Api I would say that the verbs are screwed up:
restActions : {
create : 'POST',
read : 'GET',
update : 'PUT',
destroy : 'DELETE'
},
For me the create should be a PUT and the update should be a POST. But I guess the Sencha guys have a different idea.
Btw, the source is taken from Ext 3.3.1
I guess you could override the restActions object to work as you would expect:
Ext.data.Api.restActions = {
create : 'PUT',
read : 'GET',
update : 'POST',
destroy : 'DELETE' };
As I've managed to know the Store 'id' config option is depricated.
I think the JsonStore keys off the record id on whether to do a POST vs PUT. So if the id is non-user generated the it will issue a POST, and a PUT otherwise. I am referring to record.id not record.data.id.
Not sure about the first part (my stores make the correct calls with similar code) but I can shed light on the 2nd part of your question.
Ext.data.JsonStore does NOT accept a reader object - it only takes fields and always makes its own reader, as you can see from the source
Ext.data.JsonStore = Ext.extend(Ext.data.Store, {
constructor: function(config){
Ext.data.JsonStore.superclass.constructor.call(this, Ext.apply(config, {
reader: new Ext.data.JsonReader(config)
}));
}
});
and is confirmed as being "as per docs" in Ext 2.x
http://www.sencha.com/forum/showthread.php?57189-2.x-Closed-Bug-in-Ext.data.JsonStore-cconstructor
So if you supply your own reader you must, in this case, make an Ext.data.Store instead (this caught me out too)