I have a model User
as follow:
import DS from 'ember-data';
const { attr, Model } = DS;
export default Model.extend({
name: attr("string"),
properties: attr(),
});
User.properties
is intended to hold a JSON object.
I am updating the model through a form (using ember-one-way-controls) as follow:
{{one-way-textarea
model.name
update=(action (mut model.name))}}
{{one-way-textarea
model.properties.description
update=(action (mut model.properties.description))}}
I have a button allowing the user to discard the changes by calling a discardChanges
action:
actions: {
discardChanges(model) {
model.rollbackAttributes();
},
},
The name
attribute changes are correctly discard / reset but the properties
attribute is not.
How can I handle this ?
Origin of the problem
Ember Data isn't aware of the changes because it uses ===
operator to compare the dirtied attribute against the original one. If a change has been spotted, Ember Data stores the dirtied attribute key in the _attributes
array. We notice this here. Then, when you call DS.rollbackAttributes()
, the model looks at the _attributes
to acknowledge the attributes to restore. Here it is.
But the hash aren't the same !
JS is all about value passed by reference. Here is an example from Node interpreter:
> var foo = { description: 'hello' }
undefined
> var bar = foo;
undefined
> bar.description = 'bonjour';
'bonjour'
> bar === foo
true
You are modifying the original object.
Solution
A possible solution is to deep-copy your properties
object and manually reset it when calling discardChanges
.
You can implement it as a service :
import Ember from 'ember';
const { copy, Service } = Ember;
export default Service.extend({
savedProperties: null,
finalize() {
this.set('savedProperties', null);
},
start(model) {
const properties = copy(model.get('properties'));
this.set("savedProperties", properties);
},
undo(model) {
const savedProperties = this.get('savedProperties');
for (const property in savedProperties) {
if (savedProperties.hasOwnProperty(property)) {
const keyPath = `properties.${property}`;
model.set(keyPath, savedProperties[property]);
}
}
this.set('savedProperties', null);
},
});
start
when you enter in edition mode.undo
when you want to discard the changes.finalize
when you successfully saved your record.