ember.js manually set hasDirtyAttributes not cleared when saving

2.5k Views Asked by At

I have a save button in my template that activates when the model hasDirtyAttributes

The hasDirtyAttributes flag doesn't seem to be set when a reference to a related model changes.

Example
I have a drop-down that allows picking of a related model called contact
If I change any direct attributes (e.g. name), everything works as expected, and the save button activates.
When I change the contact, it doesn't, I assume this is by design, So I set the flag when my change action is fired.

I am setting this in my route action like so:

actions:{ 

    updateProductionContact: function(contact){
         this.set('currentModel.customer.hasDirtyAttributes',true);             
         this.set('currentModel.customer.production_contact',contact);
    },
}

Now it works again. When I change a contact, the save button lights up.
However, when I now click save, the hasDirtyAttributes flag stays true (button remains active), whereas previously it was cleared until another change was made.

I would expect the framework to re-set the flag automatically after a successful save, just as before. I could of course re-set the flag on the save action of the button.

It feels like I am hacking my way around a problem, and that perhaps hasDirtyAttributes shouldn't be set manually or that I should be using a different indicator of dirtiness.

My question: How to handle this properly?

2

There are 2 best solutions below

1
On

hasDirtyAttributes is the computed property of DS.Model so you should not set it manually if you set it, then next time it will not be recalculated again. it will be updated if there is any change in the attributes.

Like Alexma suggested in comment, you can use dirtyAttributes. refer https://guides.emberjs.com/v2.13.0/models/creating-updating-and-deleting-records/#toc_persisting-records But don't set it yourself.

Refer: https://github.com/emberjs/data/blob/v2.13.0/addon/-private/system/model/model.js#L162

0
On

It turns out hasDirtyAttributes is a function/ computed property. So using set(...,true) will overwrite the function with a boolean value, which is not what we want.

There is a way for computed properties in ember to have setters and getters, but this doesn't seem to be implemented here.

I have come up with the following solution.

Basically this implements a separate custom flag for related models.

In the route's model property I have defined an additional property:

model: function(params) {
    return Ember.RSVP.hash({
       customer: this.store.findRecord('customer',params.id),
       ....
       dirtyRelations: false
    });
}, ...

Then I set this manually when a related model is changed

updateProductionContact: function(contact){
     this.set('currentModel.dirtyRelations',true);             
     ...
}, ...

And my save function sets it back to false.

updateCustomer:  function(){
     this.get('currentModel.customer').save();
     this.set('currentModel.dirtyRelations',false);
}

My template.hbs checks for either hasDirtyAttributes OR dirtyRelations

{{#if (or model.customer.hasDirtyAttributes model.dirtyRelations)}}
    highlighted save
{{else}}
    plain save
{{/if}}

So far this seems to be working well. I can take advantage of the automatic dirty tracking for normal properties.