ember-data-model-fragments
ember-data-model-fragments copied to clipboard
Polymorphic not working?
Hi, I've been trying to get polymorphic records to work for the past day with no success.
I believe I have followed the instructions correctly and I have searched the open and closed issues but still no go. They work fine to an extent. However when instantiating the object it always gives me the parent object properties only.
I have a section which has an array of custom fields. Those custom fields are polymorphic
models/section.js
export default Fragment.extend({
name: attr('string'),
fields: fragmentArray('custom-field', { polymorphic: true, typeKey: 'fieldTypeName', defaultValue: []})
});
model/custom-field.js
export default Fragment.extend({
fieldTypeName: attr('string'), //this comes in as custom-field-textbox
description: attr('string'),
model/custom-field-textbox.js
import CustomField from './custom-field';
export default CustomField .extend({
maxCharacterLimit: attr('number'),
});
serializers/custom-field.js
serialize(record, options) {
let json = this._super(...arguments);
if (record instanceof BookingFormFieldTextbox) {
json.maxCharacterLimit = record.get('maxCharacterLimit');
}
return json;
}
});
// serializers/custom-field-textbox.js
import BookingFormFieldSerializer from './booking-form-field';
export default BookingFormFieldSerializer;
The API sends:
MaxCharacterLimit":50,
"FieldTypeName":"custom-field-textbox",
"Description":"textbox limit 60"}]
After the normalize function is called what I have is something like:
{data: {
attributes: {
fieldTypeName: "custom-field-textbox",
fieldType 6,
identity: 1,
description: '',
},
type: 'custom-field'
}
However then calling maxCharacterLimit returns null.
Should the type be custom-field
or custom-field-textbox
?
Also when I use createFragment('custom-field-textbox'..) it works fine and I can see and use the property maxCharacterLimit. I then do a PUT to save it and the model in Ember still shows the property. However when I refresh so that it reloads the data from the server it instantiates the custom-field object but no properties of the custom-field-textbox are seen.
Any ideas why this is not working?
Thanks in advance.
I might have figured out why this is happening, The serializer for custom-field is being called:
normalize(type, payload, prop) {
return this._super(...arguments);
}
The type is always myapp@model:custom-field
even when the typeKey value is 'custom-field-textbox'. Not sure if that's intended. I also noticed that custom-field-textbox
serializer is never called:
import JSONSerializer from 'ember-data/serializers/json';
export default JSONSerializer.extend({
normalize(type, payload, prop) { // Never gets called
let results = this._super(type, payload, prop);
return results;
}
});
So what I had to do was in the custom-field serializer check for the fieldTypeName and set the proper factory with:
//serializers/custom-field.js
normalize(type, payload, prop) {
type = this.store.modelFactoryFor(payload.fieldTypeName);
let results = this._super(type, newPayload, prop);
return results;
}
My custom-field-textbox properties now work together with the parents properties.
Not sure if this is the way it should work but I hope it helps someone.
I have just run into the same issue, I think.
I'm using a dynamic fragment with a set of polymorphic child fragments. Each child fragment has a defaultValue
object set with the according typeKey
property.
- If the adapter can't find any data, everything is working fine, because of the correct
defaultValue
. - Saving the data with a custom
serialize
method which is checking thesnapshot.record
instance and applying thetypeKey
property afterwards, like described in the readme, is also working fine. - Loading from a valid adapter response does not work, because the
data[ typeKey ]
value seems to be missing in the fragment'sgetActualFragmentType
method.
The reason for this is the JSONSerializer, which is stripping off the typeKey
property from the data in its extractAttributes
method. This has fixed the issue for me:
// child-serializer.js
import JSONSerializer from "ember-data/serializers/json";
import typeKey from "child-fragment-typekey";
import children from "all-of-my-child-fragments";
const { hasOwnProperty } = {};
export default JSONSerializer.extend({
/**
* @param {Snapshot} snapshot
* @param {Model} snapshot.record
* @returns {Object}
*/
serialize({ record }) {
const json = this._super( ...arguments );
for ( const [ name, child ] of children ) {
if ( record instanceof child ) {
json[ typeKey ] = `child-${name}`;
break;
}
}
return json;
},
/**
* Fix removal of the `typeKey` property
* @param {Model} modelClass
* @param {Object} [data]
* @returns {Object}
*/
extractAttributes( modelClass, data ) {
const attributes = this._super( ...arguments );
if ( data && hasOwnProperty.call( data, typeKey ) ) {
attributes[ typeKey ] = data[ typeKey ];
}
return attributes;
}
});