PDA

View Full Version : multiple hasOne relation for same model delivers wrong modeldata



JanvandeKlok
5 Sep 2013, 12:10 AM
Hello,
We're using Ext 4.2

I ran into the following problem: I have multiple hasOne relations using the same model. When I access the data from the associated getters for these relation, the both deliver the same data, (being the data of the first defined association.
If I look at the raw data of the FormDefinition object the title and helptext values are different.
But the result of the formDefinition.getTitle() and formDefinition.getHelpText() are the same , they both deliver the helptext value (which is the first defined hasOne relation )

Is this a bug in Ext or am I doing something wrong???

Any help is greatly appreciated..

Jan van de Klok

Here is my code snippit for the models:

Ext.define('FormEngine.model.FormDefinition', {
extend : 'Ext.data.Model',
idProperty : 'id',
fields : ['absolutPath', 'id', 'description', 'uuid', 'lastModified', 'lastModifiedBy', 'startStage, endStage'],
hasOne : [{
model : 'FormEngine.model.MultiLingualText',
getterName : 'getTitle',
associationKey : 'title'


},
{
model : 'FormEngine.model.MultiLingualText',
getterName : 'getHelpText',
associationKey : 'helpText'
}
],
...
Ext.define('FormEngine.model.MultiLingualText', {
extend : 'Ext.data.Model',
hasMany : [{
model : 'FormEngine.model.I18NText',
associationKey : 'multilingualDescriptions',
name : 'getI18nTexts'
}
]
}

Ext.define('FormEngine.model.I18NText', {
extend : 'Ext.data.Model',
fields : ['languageCode', 'text'],
idProperty : 'languageCode',
validations : [
{type: 'length', field: 'languageCode', min: 2, max: 2},
{type: 'presence', field: 'text'}
]
});


Here is the json that is loaded :


[{"description":"My first Form en dan blablabla","title":{"multilingualDescriptions":[{"text":"My first Form","languageCode":"nl"}]},"absolutPath":"/STLK/form_engine/My_first_Form","startStage":1,"widgets":[{"id":"/txtfld1","defaultValue":"xx","staticPossibleValueListResource":null,"label":{"multilingualDescriptions":[{"text":"Label bij het w1","languageCode":"nl"}]},"clientAccess":"true","validationErrorMessage":{"multilingualDescriptions":[]},"possibleValueListResource":null,"elementPath":"/xx/path/something","requiredField":true,"knowledgeworkerAccess":"1","widgetXType":"textfield","width":300,"helpText":{"multilingualDescriptions":[{"text":"Helptekst bij het w1","languageCode":"nl"}]}},{"id":"/cmbbx1","defaultValue":"3","staticPossibleValueListResource":{"commaSeparatedValues":"1,2,3,4","displayLabels":{"multilingualDescriptions":[{"text":"Een, Twee, Drie, Vier","languageCode":"nl"}]}},"label":{"multilingualDescriptions":[{"text":"Label bij het w2","languageCode":"nl"}]},"clientAccess":"true","validationErrorMessage":{"multilingualDescriptions":[]},"possibleValueListResource":null,"elementPath":"/xx/path/something w2","requiredField":false,"knowledgeworkerAccess":"0","widgetXType":"combobox","width":500,"helpText":{"multilingualDescriptions":[{"text":"Helptekst bij het w2","languageCode":"nl"}]}}],"helpText":{"multilingualDescriptions":[{"text":"Helptekst bij het formulier","languageCode":"nl"}]},"endStage":0,"name":null,"id":"id_My_first_Form","lastModified":1378365784812,"version":null,"active":false,"lastModifiedBy":"admin"},{"description":"My complex form en dan blablabla","title":{"multilingualDescriptions":[{"text":"My complex form","languageCode":"nl"}]},"absolutPath":"/STLK/form_engine/My_complex_form","startStage":1,"widgets":[{"id":"/txtfld1","defaultValue":"xx","staticPossibleValueListResource":null,"label":{"multilingualDescriptions":[{"text":"Label bij het w1","languageCode":"nl"}]},"clientAccess":"true","validationErrorMessage":{"multilingualDescriptions":[]},"possibleValueListResource":null,"elementPath":"/xx/path/something","requiredField":true,"knowledgeworkerAccess":"1","widgetXType":"textfield","width":300,"helpText":{"multilingualDescriptions":[{"text":"Helptekst bij het w1","languageCode":"nl"}]}},{"id":"/cmbbx1","defaultValue":"3","staticPossibleValueListResource":{"commaSeparatedValues":"1,2,3,4","displayLabels":{"multilingualDescriptions":[{"text":"Een, Twee, Drie, Vier","languageCode":"nl"}]}},"label":{"multilingualDescriptions":[{"text":"Label bij het w2","languageCode":"nl"}]},"clientAccess":"true","validationErrorMessage":{"multilingualDescriptions":[]},"possibleValueListResource":null,"elementPath":"/xx/path/something w2","requiredField":false,"knowledgeworkerAccess":"0","widgetXType":"combobox","width":500,"helpText":{"multilingualDescriptions":[{"text":"Helptekst bij het w2","languageCode":"nl"}]}}],"helpText":{"multilingualDescriptions":[{"text":"Helptekst bij het formulier","languageCode":"nl"}]},"endStage":0,"name":null,"id":"id_My_complex_form","lastModified":1378365785376,"version":null,"active":false,"lastModifiedBy":"admin"}]

ettavolt
6 Sep 2013, 3:40 AM
Internally Ext stores references as instanceName fields of record object. You probably will want to configure this property of associations.

RoyalSens
5 May 2014, 6:07 AM
I've got the same problem. I have 'parent' model with two associations to the same child model. The difference between those two are the foreign_key's in the parent model.
However, the associated data is the same...

I cannot get the proposed solution with 'instanceName' working. Because I don't have an 'instanceName' property in Sencha Architect on the association and therefore cannot configure it.

I sort of fixed it by overriding the constructor of Ext.data.association.HasOne:


Ext.applyIf(this, {
associatedName: config.associationKey + 'HasOneInstance'
});
this.callParent(arguments);

However, this breaks lazy loading of the associated data with the following error:


model.getter()
TypeError: undefined is not a function



So is there a solution for this?

RoyalSens
6 May 2014, 1:50 AM
I think I've got a solution, but I'm not sure if there are any implication further down the line. Maybe somebody else sees problems or can use this code as well.

I've created overrides for Ext.data.association.HasOne and Ext.data.association.Association.
In the first I've overriden the createGetter method and changing the instance creation line. There was a reference to 'associatedName' and I've changed it to 'associatedModel.$className'.
In the second one I've changed the 'associatedName' to be unique. Because that influences some later lines of code, I've updated some of those as needed.



Ext.define('MyApp.override.data.association.HasOne', {
override: 'Ext.data.association.HasOne',

createGetter: function() {
var me = this,
ownerModel = me.ownerModel,
associatedName = me.associatedName,
associatedModel = me.associatedModel,
foreignKey = me.foreignKey,
primaryKey = me.primaryKey,
instanceName = me.instanceName;

return function(options, scope) {
options = options || {};
var model = this,
foreignKeyId = model.get(foreignKey),
success,
instance,
args;
if (options.reload === true || model[instanceName] === undefined) {
instance = Ext.ModelManager.create({}, associatedModel.$className);
instance.set(primaryKey, foreignKeyId);
if (typeof options == 'function') {
options = {
callback: options,
scope: scope || model
};
}
success = options.success;
options.success = function(rec){
model[instanceName] = rec;
if (success) {
success.apply(this, arguments);
}
};
associatedModel.load(foreignKeyId, options);
model[instanceName] = instance;
return instance;
} else {
instance = model[instanceName];
args = [instance];
scope = scope || options.scope || model;
Ext.callback(options, scope, args);
Ext.callback(options.success, scope, args);
Ext.callback(options.failure, scope, args);
Ext.callback(options.callback, scope, args);
return instance;
}
};
}
});

Ext.define('MyApp.override.data.association.Association', {
override: 'Ext.data.association.Association',

constructor: function(config) {
Ext.apply(this, config);

var me = this,
types = Ext.ModelManager.types,
ownerName = config.ownerModel,
associatedName = config.associatedModel + (++me.statics().AUTO_ID),
ownerModel = types[ownerName],
associatedModel = types[config.associatedModel],
associationKey = config.associationKey,
keyReIdx;


if (associationKey) {
keyReIdx = String(associationKey).search(/[\[\.]/);
if (keyReIdx >= 0) {
me.associationKeyFunction = Ext.functionFactory('obj', 'return obj' + (keyReIdx > 0 ? '.' : '') + associationKey);
}
}


me.initialConfig = config;
me.ownerModel = ownerModel;
me.associatedModel = associatedModel;
Ext.applyIf(me, {
ownerName : ownerName,
associatedName: associatedName
});
me.associationId = 'association' + (me.statics().AUTO_ID);
}
});


In case this works in all cases, I would like to see this included in a next release.