We are using ember-changeset to handle our data in forms. Data flow is usually like this: input -> changeset -> model -> server -> model -> changeset -> input
. User change some input which is reflected in changeset and validated. When user presses submit
changeset is baked into model which is then saved.
And here is the problem. If server refuses to accept changes then we end up with model in broken state. To overcome this we implemented custom save
method to mimic what model.save
does. But it uses private methods and since ember-data@2.10
not working on relations - or to be more precise it works but does not wait for them to reload.
Any help or idea would be greatly appreciated.
/*
* Saves an object by saving changes taken from a changeset.
* Updates the target object if the operation succeeds.
* @param changeset the changeset to save
* @return {Promise} a promise that resolves to an object returned by the server
*/
saveChangeset(changeset) {
const record = changeset.get('_content'); // not entirely a public field
const id = record.get('id');
const constructor = record.get('constructor');
const modelName = constructor.modelName;
const snapshot = changesetToSnapshot(changeset);
const operation = record.get('isNew') ? 'createRecord' : 'updateRecord';
record._internalModel.adapterWillCommit();
return this.adapterFor(modelName)[operation](this, constructor, snapshot)
.then(res => {
// propagate the changes
const model = this.modelFor(modelName);
const serializer = this.serializerFor(modelName);
const payload = serializer.normalizeResponse(this, model, res, id, operation);
if (payload.included) {
this.push({data: payload.included});
}
this.didSaveRecord(record._internalModel, {data: payload.data});
changeset.rollback();
return res;
});
},
/**
* Creates s snapshot-like object based on a changeset.
*/
export default function changesetToSnapshot(changeset) {
const model = changeset.get('_content'); // not entirely a public field
const isNew = model.get('isNew');
const id = model.get('id');
const constructor = model.get('constructor');
const modelName = constructor.modelName;
const changes = {};
changeset.get('changes').forEach(change => {
changes[change.key] = null; // The value does not matter
});
const filterByName = fn => (name, meta) => { // eslint-disable-line func-style
if (name in changes) {
fn(name, meta);
}
};
const fieldFilter = isNew ? fn => fn : filterByName;
return { // emulate a snapshot
_isChangeset: true,
type: constructor,
record: model,
modelName,
id,
eachAttribute: fn => model.eachAttribute(fieldFilter(fn)),
eachRelationship: fn => model.eachRelationship(fieldFilter(fn)),
attr: key => changeset.get(key),
belongsTo(key, options) {
assert('Snapshot from changeset can only return the id of a belongsTo relationship, not a snapshot of it', options && options.id);
return get(changeset, key + '.id');
},
hasMany(key, options) {
assert('Snapshot from changeset can only return the ids of a hasMany relationship, not an array of snapshots', options && options.ids);
return changeset.get(key).map(e => e.get('id'));
},
};
}
Aucun commentaire:
Enregistrer un commentaire