So, I have a problem using Sencha ExtJs 4.1 Associations.
I have something like:
Models
Ext.define('Tpl.model.User', {
extend: 'Ext.data.Model',
requires: ['Tpl.model.PostTemplate'],
fields: [
{ name: 'id', type: 'int' },
{ name: 'name', type: 'string' },
{ name: 'postTemplate', type: 'int' }
],
associations: [
{ type: 'belongsTo', name: 'postTemplate', model:'Tpl.model.PostTemplate', associationKey: 'postTemplate', primaryKey: 'id', foreignKey: 'postTemplate' }
]
});
and
Ext.define('Tpl.model.PostTemplate', {
extend: 'Ext.data.Model',
fields: [
{ name: 'id', type: 'int' },
{ name: 'blah', type: 'string' }
],
associations: [
{ type: 'hasMany', model: 'Tpl.model.User' }
]
});
Stores
Ext.define('Tpl.store.Users', {
extend: 'Ext.data.Store',
model: 'Tpl.model.User',
autoLoad: true,
proxy: {
type: 'rest',
url: '../users',
reader: {
type: 'json',
root: ''
},
writer: {
type: 'json'
}
}
});
Ext.define('Tpl.store.PostTemplate', {
extend: 'Ext.data.Store',
model: 'Tpl.model.PostTemplate',
autoLoad: true,
proxy: {
type: 'rest',
//appendId: true,
url: '../postTemplates/',
reader: {
type: 'json',
root: ''
},
writer: {
type: 'json'
}
}
});
The problem is that I'm getting a POST like this:
{
"postTemplate": 1,
"id": 0,
"name": "foo"
}
But I need a POST like this:
{
"postTemplate": {
"id": 1,
"blah": "foo"
},
"id": 0,
"name": "bar"
}
Also, the assessor function like "setPostTemplate" doesn't exist and I think it should be created automatically.
Already tried to something like " record.data.postTemplate = (...) " but I got an infinite loop throwing an execption...
Can someone please advise? Also, if you need something else that could be useful for the answer let me know.
Thanks!
Out of the box the Associated objects are not serialized back to the server as you expect them . This issue has been brought up many times. The best thing might be to follow this thread:
http://www.sencha.com/forum/showthread.php?141957-Saving-objects-that-are-linked-hasMany-relation-with-a-single-Store
This thread talks about overriding getRecordData in the JSON writer class.
Related
I am using ExtJS 6.x with three models:
Ext.define('Admin.model.Patient', {
extend: 'Ext.data.Model',
requires: [
'Ext.data.proxy.Rest',
'Ext.data.schema.Association'
],
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' },
],
style: {
'font-size': '22px',
'color':'red'
},
proxy: {
type: 'ajax',
url: remote.url.patient,
reader: {
type: 'json',
rootProperty: ''
}
}
});
Ext.define('Admin.model.LabResultGroup', {
extend: 'Ext.data.Model',
idProperty: 'id',
fields: [
{ name: 'test_code', type: 'string' },
{ name: 'test_name', type: 'string' },
{
name: 'patient_id',
type: 'string',
reference: {
parent: 'Patient',
inverse: 'lab_results',
autoLoad: false
}
}
],
proxy: {
type: 'ajax',
url: remote.url.labsgroup,
reader: {
type: 'json',
rootProperty: ''
}
});
and
Ext.define('Admin.model.LabResult', {
extend: 'Ext.data.Model',
idProperty: 'id',
fields: [
{ name: 'test_code', type: 'string' },
{ name: 'test_name', type: 'string' },
{ name: 'test_code_system', type: 'string' },
{ name: 'result_value', type: 'string' },
{ name: 'result_value_num', type: 'string' },
{ name: 'collection_datetime', type: 'date', format: 'Y-m-d' },
{ name: 'result_datetime', type: 'date', format: 'Y-m-d' },
{
name: 'lab_id',
type: 'string',
reference: {
parent: 'LabResultGroup',
inverse: 'lab_group',
autoLoad: false
}
}
],
proxy: {
type: 'ajax',
url: remote.url.labs,
reader: {
type: 'json',
rootProperty: ''
}
}
});
I can access the association between LabResultGroup and Patient just fine (between two comboboxes using bindings), but when I try accessing the association between LabResult and LabResultGroup, it does not register.
I will post a Fiddle in due course to exhibit the behavior I am encountering. Is there anything that would prevent associations across models like this?
It actually worked! For some odd reason the parent name in the association on my LabResult model got mucked up. Corrected that, and my association bindings are firing as expected.
(Also, there was a minor problem with the API endpoint I was accessing. I had to add another condition for the property on which it was filtering. Details, shmetails)
Moral of the story: Names are important! Happy Friday peeps! Ha! Ha!
I'm using Sencha Touch 2.4, with Sencha Cmd 6.1.x (so I believe I'm using Ext JS 6). I've got the following model and store:
Ext.define('App.model.User', {
extend: 'Ext.data.Model',
fields: [{
name: 'organizationId',
type :'int',
reference: {
type: 'Organization',
association: 'UsersByOrganization',
role: 'organization',
inverse: 'users'
}
}, {
"name": "matricola",
"type": "int"
}]
});
and
Ext.define('App.model.Organization', {
extend: 'Ext.data.Model',
fields: ['name']
});
I load my stores (with a 'sql' proxy) using the usual way, but I cannot find my reference anywhere. I simply get the records and I cannot call "users" or its inverse.
Any idea?
Sencha Touch 2.4 and ExtJS 6 are two different toolkits. Syntax for creating models and stores are similar in both, but not in all cases.
I believe what you are looking for is the StoreManager. If you have defined a store like so:
Ext.define('App.store.User', {
extend: 'Ext.data.Store',
storeId: 'User',
model: 'User'
});
Then you can reference the store like so:
// Return a list of users
Ext.getStore('User').getRange();
The code below works for me on Ext JS 6. Maybe you can model yours after this example:
Ext.define('App.model.Customer', {
extend: 'Ext.data.Model',
idProperty: 'customerNumber',
fields: [
{ name: 'customerNumber', type: 'int' },
{ name: 'customerName', type: 'string' },
{ name: 'contactLastName', type: 'string' },
{ name: 'contactFirstName', type: 'string' }
],
proxy: {
type: 'ajax',
url: '../../../api/CustomersAssociationsReference',
reader: {
type: 'json',
rootProperty: 'customers',
totalProperty: 'count'
}
}
});
Ext.define('App.model.Order', {
extend: 'Ext.data.Model',
idProperty: 'orderNumber',
fields: [
{ name: 'orderNumber', type: 'int' },
{
name: 'customerNumber', reference: {
type: 'App.model.Customer',
inverse: 'orders'
}
},
{ name: 'orderDate', type: 'string' },
{ name: 'status', type: 'string' }
],
proxy: { // Note that proxy is defined in the Model, not the Store
type: 'ajax',
url: '../../../api/OrdersAssociationsReference',
reader: {
type: 'json',
rootProperty: 'orders',
totalProperty: 'count'
}
}
});
Ext.application({
name: 'App',
models: ['Customer', 'Order'],
stores: ['Customers', 'Orders'],
launch: function () {
var customersStore = Ext.getStore('Customers');
customersStore.load(function (records, operation, success) {
var customer = records[0],
orders = customer.orders(),
order;
orders.load(function (records, operation, success) {
console.log('Orders for ' + customer.get('customerName') + ':\n-------------------------------------------------------');
for (i = 0, len = records.length; i < len; i++) {
order = records[i];
console.log('orderNumber: ' + order.get('orderNumber'));
console.log('orderDate: ' + order.get('orderDate'));
console.log('status: ' + order.get('status'));
console.log('-------------------------------');
}
})
});
}
});
I have the following JSON structure:
userAuth
----userAccount -- hasOne
----userAccountDetails -- hasMany
I want to show a form that shows data from userAuth and userAccount and then a grid with a row for each row in userAccountDetails
Here is the code for userAuth model:
Ext.define('xxxx.model.UserAuth', {
extend: 'Ext.data.Model',
fields: [
{ name: 'id' },
{ name: 'email' },
{ name: 'userName' },
{ name: 'refIdStr' },
{ name: 'displayName' },
{ name: 'modifiedDate', type: 'date', }
],
requires: [
'xxxx.model.UserAccount',
'xxxx.model.UserAuthDetails',
],
hasMany: [
{
model: 'xxxx.model.UserAuthDetails',
name: 'authDetails',
foreignKey: 'userAuthId',
associationKey: 'userAuthDetails',
}
],
hasOne: [
{
model: 'xxxx.model.UserAccount',
name: 'userAcount',
associationKey: 'userAccount',
getterName: 'getUserAccount',
setterName: 'setUserAccount',
}
],
proxy: {
type: 'ajax',
startParam: 'skip',
limitParam: 'take',
url: settings.ApiUrl + '/model/UserAuth/?format=json',
baseParams: {
skip: '0',
take: '10',
},
reader: {
type: 'json',
root: 'results',
successProperty: 'success',
totalProperty: 'totalCount'
}
}
});
And userAccount model
Ext.define('xxxx.model.UserAccount', {
extend: 'Ext.data.Model',
fields: [
{ name: 'username' },
{ name: 'id' },
{ name: 'name' },
{ name: 'email' },
{ name: 'slug' },
{ name: 'facebookId' }
],
belongsTo: 'xxxx.model.UserAuth',
proxy: {
type: 'ajax',
startParam: 'skip',
limitParam: 'take',
url: settings.ApiUrl + '/model/UserAccount/?format=json',
baseParams: {
skip: '0',
take: '10',
},
reader: {
type: 'json',
root: 'results',
successProperty: 'success',
totalProperty: 'totalCount'
}
}
});
and userAuthDetails:
Ext.define('xxxx.model.UserAuthDetails', {
extend: 'Ext.data.Model',
fields: [
{ name: 'id' },
{ name: 'userAuthId' },
{ name: 'provider' },
{ name: 'userId' },
{ name: 'userName' },
{ name: 'displayName' },
{ name: 'firstName' },
{ name: 'lastName' },
{ name: 'email' },
{ name: 'modifiedDate' },
{ name: 'provider' },
],
belongsTo: [
{
model: 'xxxx.model.UserAuth',
isntanceName: 'userAuth',
getterName: 'getUserAuthDetails',
setterName: 'setUserAuthDetails',
associationKey: 'userAuthDetails'
}
],
proxy: {
type: 'ajax',
startParam: 'skip',
limitParam: 'take',
url: settings.ApiUrl + '/model/UserAuthDetails/?format=json',
baseParams: {
skip: '0',
take: '10',
},
reader: {
type: 'json',
root: 'results',
successProperty: 'success',
totalProperty: 'totalCount'
}
}
});
Loading the store works and the associations work - when i call record.getUserAccount().get('email') it returns what I'd expect - so all that is working.
Now, my question is - how the hell do i get that data into the form described above?
I have tried doing things like:
{
xtype: 'textfield',
fieldLabel: 'username',
allowBlank: false,
maxLength: 100,
name: 'userAccount.userName'
}
thinking the association name might be a good hint for it - but that doesn't work...
Data from the top most model (userAuth) works ok - I just can't seem to pull in the hasOne
into the form.
I haven't even tried binding the userAuthDetails to a grid yet but suspect that will be equally as challenging
Has anyone managed to get this to work? I only went down the associations route because i thought it would make this sort of stuff cleaner / simpler!
[EDIT]
Giving up trying to do this with a form as I am happy for this data to be read only for now. I am now trying to show this data in an xtemplate within a row expander.
I've tried the following but it does not work!!!
plugins: [
{
ptype: 'rowexpander',
rowBodyTpl: [
'<p><b>Username:</b> {userName}</p>',
'<p><b>Email:</b> {userAccount.email}</p>',
'<tpl for="userAuthDetails">',
'<p>{provider}</p>',
'</tpl>'
]
}],
What sort of voodoo do I need to make this work? It is not obvious at all!!!
ATM I am thinking I won't be using ExtJs again - I've found myself in too many dark holes like this recently where things blatantly should just work the way you'd expect - just googling this shows everyone expects this to work. I've used ExtJs on and off for years but I think now is the time to finally admit there are better js application frameworks out there.
Unfortunately, there is no automatic, config-only way of how to do that. If you look at the loadRecord source you see that it just gets data from the passed record and calls setValues on the form.
You would need to override loadRecord method to dig the required values from the associated record(s).
i want to ask you if extjs comboboxes use filtered stores. I have a table with different kind of business(so it has a "type" field). I have a view with multiple comboboxes, and i want that those works with stores that use the same model, but with different filters. So when i put them to work, it doesn't work.
This is one of the filtered stores:
Ext.define('myapp.store.ListaAerolineas', {
extend: 'Ext.data.Store',
requires: [
'myapp.model.Empresa'
],
constructor: function(cfg) {
var me = this;
cfg = cfg || {};
me.callParent([Ext.apply({
autoLoad: true,
autoSync: true,
model: 'myapp.model.Empresa',
storeId: 'MyJsonPStore',
proxy: {
type: 'jsonp',
url: 'http://myapp.localhost/empresa/listar/',
reader: {
type: 'json',
root: 'listaempresa'
}
},
filters: {
property: 'IdTipo',
value: 5
}
}, cfg)]);
}
});
This is the model:
Ext.define('myapp.model.Empresa', {
extend: 'Ext.data.Model',
idProperty: 'Id',
fields: [
{
name: 'Id',
type: 'int'
},
{
name: 'Nombre',
type: 'string'
},
{
name: 'Direccion',
type: 'string'
},
{
name: 'Telefono',
type: 'string'
},
{
name: 'Contacto',
type: 'string'
},
{
name: 'Celular',
type: 'string'
},
{
name: 'TipoEmpresa',
type: 'string'
},
{
name: 'Estado',
type: 'string'
},
{
name: 'FechaCreacion',
type: 'date'
},
{
name: 'IdTipo',
type: 'int'
},
{
name: 'IdEstado',
type: 'int'
}
]
});
And finally this is my grid column definition for my combobox:
{
xtype: 'gridcolumn',
dataIndex: 'Aerolinea',
text: 'Aerolinea',
editor: {
xtype: 'combobox',
id: 'cmbGridListaEmbarquesAerolinea',
store: 'ListaAerolineas'
}
So, i must do anything? Thank you in advance...
What version of ExtJs are you using? but in general combobox will display only records that are filtered in the store. So, to answer your question - yes, it should work.
I need to Extjs Tree panel with dynamic remote data(JSON) for file listing.
and the date field name is not fit to Extjs tree store field. so I need to re-mapping to make fit, like adding leaf field and text field.
the return JSON data is like this:
[{
"id":1,
"yourRefNo":"A91273",
"documentName":"Test Document",
"documentFileName":"login_to_your_account-BLUE.jpg",
"updatedBy":"root root",
"updatedAt":"\/Date(1343012244000)\/"
}]
and this is the tree panel:
Ext.define('App.view.Document.DocumentList', {
extend :'Ext.tree.Panel',
rootVisible : false,
alias: 'widget.Document_list',
store: 'DocumentList_store'
});
and this is the store:
Ext.define('App.store.DocumentList_store', {
extend: "Ext.data.TreeStore",
model: 'App.model.DocumentList_model',
proxy: {
type: 'ajax',
url: '/Document/GetDocumentList/',
actionMethods: {
read: 'POST'
},
reader: {
type: 'json',
root: '' // there is no root
},
pageParam: undefined,
startParam: undefined,
pageParam: undefined
},
root: {
children: []
},
autoLoad: false,
listeners: {
append: function (thisNode, newChildNode, index, eOpts) {
console.log(newChildNode.get('documentName')); // 'Test Document'
newChildNode.set('leaf', true);
newChildNode.set('text', newChildNode.get('documentName'));
// it does not add to tree panel.
}
}
});
after load data from server, and it call the append function well. but after that, nothing show up in tree panel.
What I am doing wrong? please advice me.
Thanks
[EDIT]
This is the model,
Ext.define("App.model.DocumentList_model", {
extend: "Ext.data.Model",
fields: [
'id','yourRefNo','documentName','documentFileName','updatedBy','updatedAt'
]
});
I'm fusing your code with a piece of working code of mine. Try see if this works:
Model:
Ext.define("App.model.DocumentList_model", {
extend: 'Ext.data.Model',
fields: [
{name: 'id'},
{name: 'yourRefNo'},
{name: 'documentName' },
{name: 'documentFileName'},
{name: 'updatedBy'},
{name: 'updatedAt', convert: function(v) { return v;} }, // Notice you can do field conversion here
{name: 'leaf', type: 'boolean', defaultValue: false, persist: false},
],
proxy: {
type: 'ajax',
url: '/Document/GetDocumentList/',
actionMethods: {
read: 'POST'
},
reader: {
type: 'json',
root: 'children'
},
},
});
Store:
Ext.define('App.store.DocumentList_store', {
extend: "Ext.data.TreeStore",
model: 'App.model.DocumentList_model',
root: {
text: 'Root',
id: null,
expanded: true
},
autoLoad: false,
});
JSON Response:
{
"success":true,
"children":[{
"id":1,
"yourRefNo":"A91273",
"documentName":"Test Document",
"documentFileName":"login_to_your_account-BLUE.jpg",
"updatedBy":"root root",
"updatedAt":"\/Date(1343012244000)\/",
"leaf":false
}]
}