hasDirtyAttributes always false for nested properties

I’m using the latest Ember Data via Ember CLI. The problem is that the model never gets into a dirty state when any of its nested properties are modified.

JSON:

{
  id: 1,
  name: 'page_1',
  content: [{
    name: 'title',
    value: {
      en: 'Home page',
      de: 'Startseite'
    }
  }]
}

Model:

export default DS.Model.extend({
    name: DS.attr('string'),
    fields: DS.attr()
});

Handlebars:

<p>Is dirty: {{model.hasDirtyAttributes}}</p>
<p>Works: {{input type="text" value=model.name}}</p>
<p>Does not work: {{input type="text" value=model.content.name}}</p>

Changing model.name works fine. Changing model.content.name the changes are made to the record, but hasDirtyAttributes is false. Any clue?

I’ve run into this as well. Basically, because you haven’t defined the sub-properties explicitly in the model (or in their own separate model, see #1 below), Ember doesn’t know to bind to the properties in the same way as those explicitly defined in the model (viz., it doesn’t).

You can get around this a couple ways: 1) you can define sub-models and use embedded models, but all sub-models need to have their own unique Id’s (even if you’re using the embedded mixin)—this was a deal-breaker for me, so I went with, 2) use the Ember Data Model Fragments library. It has worked really well for me, however, it’s only compatible up to v1.0.0-beta.18, so caveat developer.

Hope that helps!

Thanks! I’ll consider using Ember Data Model Fragments although I’m not very comfortable sticking to some old beta version of Ember Data. Guess that’s a tradeoff. I thought Ember Data supported JSON API out of the box but now I got an impression one can only do a todolist type of app with it. Not very ambitious, is it? :wink:

Yes, Ember-Data supports JSONAPI out-of-the-box, but what you have here doesn’t follow the JSONAPI spec. I suspect you’re actually just using the default (pre-2.0) REST adapter, which deals with “JSON APIs,” (viz. an API that sends JSON), but not specifically with the spec I mentioned above.

The Model-Fragments library should be updated relatively soon—which doesn’t help you today, but it might be worth dealing with a slightly older version of Ember Data for the short term, if you really want this feature. Otherwise you’ll need to refactor your API (unless someone has a better option!).

Edit: also, it looks like there’s a PR for compatibility with 1.13.x

I did use JSONAPI adapter & serializer along with a JSON API backend. The JSON I posted is a simplified model that’s coming straigth outta Mongo DB. By the time it reaches my Ember app, it’s transformed to a proper format as per JSON API spec (id, type, attributes, etc.). I gave Ember Data Model Fragments a shot and oh boy it does wonders! Despite my console filled up with all sorts of deprecations, it does seem to work just fine. Thanks for bringing it to my attention!

Glad to hear it. Best of luck—and hopefully those deprecation warnings will subside soon!

One way to deal with this problem is to re-assign the property.

For example, if you have the following structure:

export default DS.Model.extend({
  nested: DS.attr(), // This is an object
});

And you want to change one of the inner properties:

this.set('nested.innerProperty', 'whatever');

You’ll have to do it as follows:

this.set('nested', {
  ...this.get('nested'),
  innerProperty: 'whatever',
});

This way, the reference to the nested model will change and the model will be considered as dirty and lastly, it will appear in .changedAttributes() call as well.

1 Like