[4.1 RC3] CopyFrom model not copy hasmany
REQUIRED INFORMATION
Ext version tested:
Browser versions tested against:
Description:
- When I save a model with a hasmany property, the model is updated on the server correctly. But when the model is interpreted by the EXTJS the child relations are not updated correctly.
After some debugging, I found that the Ext.data.Operation method uses the commitRecords method to copy the server record to the client record.
The server record is OK, but the client record doesn´t have its child’s updated after the copyFrom method.
Steps to reproduce the problem:
The result that was expected:
- Orginal and Copy is equal
The result that occurs instead:
- Original and Copy is different
Test Case:
Code:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1" />
<link rel="stylesheet" type="text/css" href="http://dbs-gmf-service/extjs/ext-4.1/resources/css/ext-all-gray.css" />
</head>
<body>
</body>
<script type="text/javascript" src="http://dbs-gmf-service/extjs/ext-4.1/ext-all-debug.js"></script>
<script type="text/javascript">
Ext.onReady(function(){
Ext.define('GMF.model.DTODeTelefone', {
extend: 'Ext.data.Model'
,fields: [
{ name: 'Id'}
,{ name: 'Telefone'}
]
,proxy: {
type: 'rest',
url: '/Apresentacao/Telefone'
, api: {
read: '/Apresentacao/Telefone/',
create: '/Apresentacao/Telefone/Novo',
update: '/Apresentacao/Telefone/Editar',
destroy: '/Apresentacao/Telefone/Excluir'
}
, actionMethods: {
create: 'POST',
read: 'GET',
update: 'POST',
destroy: 'POST'
}
, reader: { root: 'Entidade' }
}
,idProperty : 'Id'
});
Ext.define('GMF.model.DTODePessoaTelefone', {
extend: 'Ext.data.Model'
,fields: [
{ name: 'ID'}
,{ name: 'Nome'}
,{ name: 'NomeDaMae'}
,{ name: 'CPF'}
]
,proxy: {
type: 'rest',
url: '/Apresentacao/PessoaTelefone'
, api: {
read: '/Apresentacao/PessoaTelefone/',
update: '/Apresentacao/PessoaTelefone/Editar'
}
, actionMethods: {
create: 'POST',
read: 'GET',
update: 'POST',
destroy: 'POST'
}
, reader: { root: 'Entidade' }
}
, hasMany: [
{ model: 'GMF.model.DTODeTelefone', name: 'Telefones' }
]
, idProperty: 'ID'
});
var pessoaTelefone = Ext.create('GMF.model.DTODePessoaTelefone');
var telefone = Ext.create('GMF.model.DTODeTelefone');
pessoaTelefone.Telefones().add(telefone);
var pessoaTelefoneCopy = Ext.create('GMF.model.DTODePessoaTelefone');
pessoaTelefoneCopy.copyFrom(pessoaTelefone);
document.body.innerHTML = 'Copy: ' + pessoaTelefoneCopy.Telefones().count();
document.body.innerHTML += '<br/>';
document.body.innerHTML +='Original: ' + pessoaTelefone.Telefones().count();
});
</script>
HELPFUL INFORMATION
Debugging already done:
- commitResults in Ext.data.Operation
Operating System:
Another version of copyFrom that loads associated data
I too stumbled upon this problem. This is the version we're using now. it's a bit better in that it doesn't unnecessarily delete the store or existing records if not needed. Might help someone who expects save() on a model to update associated records from server response too.
Code:
// Override proxy reader so that it loads nested data from server response on model save()
Ext.override(Ext.data.Model, {
copyFrom: function (sourceRecord) {
var result = this.callParent(arguments);
var n = 0;
var me = this;
if (sourceRecord && sourceRecord.associations.length) {
for (assocCount = sourceRecord.associations.length; n < assocCount; n++) {
association = sourceRecord.associations.getAt(n);
if (association.type === 'belongsTo')
{
break;
}
var storeName = association.storeName;
if (typeof (me[storeName]) === 'undefined') {
me[storeName] = Ext.clone(sourceRecord[storeName]);
}
// We don't want to replace the store if it already exists as it could have events bound already
else {
// The result could be without the store entirely since the server deemed nothing changed.
// If the server want's to tell us that all items in the association have been removed it must send an empty array in json response.
if (sourceRecord[storeName]) {
var
toAdd = [],
toRemove = [];
// Add new records, update existing records (again existing records may have event handlers bound so we can't just replace them)
sourceRecord[storeName].each(function (record) {
var meRecord = me[storeName].getById(record.get('id'));
if (meRecord) {
meRecord.copyFrom(record);
}
else {
toAdd = record;
}
}, this);
me[storeName].add(toAdd);
// Remove removed records
me[storeName].each(function (record) {
if (sourceRecord[storeName].getById(record.get('id') === null)) {
toRemove.push(record);
}
}, this);
me[storeName].remove(toRemove);
}
}
}
}
return result;
},
});