# How to handle object/array attributes

**URL:** https://discuss.emberjs.com/t/how-to-handle-object-array-attributes/7583
**Category:** Ember Data
**Created:** [March 20, 2015, 6:49pm UTC](https://discuss.emberjs.com/t/how-to-handle-object-array-attributes/7583 "2015-03-20T18:49:07Z")
**Posts on this page:** 4
**Page:** 1

<div class="post-metadata">

### Author: ![gniquil](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/gniquil/32/5014_2.png) [@gniquil](https://discuss.emberjs.com/u/gniquil)
#### Post date: [March 20, 2015, 6:49pm UTC](https://discuss.emberjs.com/t/how-to-handle-object-array-attributes/7583/1 "2015-03-20T18:49:07Z")

</div>

Hi all,

I have a rails model that’s translated to model definition like this:

```javascript

export default DS.Model.extend({
  name: DS.attr('string'),
  settings: DS.attr(), // in rails, its a JSON object
  tags: DS.attr(), // in rails its again an Array object, which actually models a "set"
  ..
});

```

To make it easier to work with these attributes, I created special transfroms that converts settings into a special object and tags into a `set`.

However, when I want to update the attributes in settings, or add/remove items from tags, I always had to copy the original object, then update, and finally replace the original with the newly modified object. This way dirty tracking works. However, is there a way for me to update attributes or add/remove objects in place and still trigger dirty? And if there’s an API to mark things dirty, how would rollback work? Generally are there api where I can implement dirty tracking? Ideally what I would like to is the following

```javascript
user = User.create();
// user.get('isDirty') === false; user.get('settings.isAwesome') === false;
user.get('settings').set('isAwesome', true);
// user.get('isDirty') === true; user.get('settings.isAwesome') === false;
user.rollback();
// user.get('isDirty') === false; user.get('settings.isAwesome') === false;

```

Any thoughts?

---

<div class="post-metadata">

### Author: ![gniquil](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/gniquil/32/5014_2.png) [@gniquil](https://discuss.emberjs.com/u/gniquil)
#### Post date: [March 20, 2015, 7:38pm UTC](https://discuss.emberjs.com/t/how-to-handle-object-array-attributes/7583/2 "2015-03-20T19:38:42Z")

</div>

Thinking about this at a high level. I think in order to make this work, here are a few recommendations:

First, provide a special type of attr:

```javascript
// note below we need a different `attr` is because the associated transform need to be given the model object
// see later sections why
export default DS.Model.extend({
  settings: DS.observedAttr('settings'), // settings is a special type of transform
  ...
});

```

Second, provide a special type of base transform

```javascript
// in app/transforms/settings
export default DS.ObservedTransform.extend({
  serialize: ... // as normal
  deserialize: ... // as normal
  serializeOnChange: function(deserialized) {
    /*
     * the parent model will call this method when it is notified that this attribute has been changed. 
     * the result from this method will be in the changes array
     */
     return this.serialize(deserialized); // default implementation is just serialize the attribute again
  },
  deserializeOnRollback: function(serialized) {
    /*
     * the parent model will call this method when rollback happens, the transform will be able to 'restore'
     * to the original state
     */
     return this.deserialize(serialized); // default implmentation is again the same as on first load
  },
});

```

Finally, the `DS.ObservedTransform` should come with the following:

```javascript
// in observed-transform
export default DS.Transform.extend({
  notifyChange: function() {
    /*
     * The following method on the model, once called, will use the serializeOnChange/deserializeOnChange
     * method to track dirtiness/store changes
     */
    this.model.notifyObservedAttributeChanged(this); 
  });
  .. some other magic
});

```

Now with all the above stuff done, we could do the following in the settings transform

```javascript
// in app/transforms/settings
let Settings = Ember.Object.extend({
  update: function(key, val) {
    this.set(key, val);
    this.transform.notifyChange();
  },
});

Settings.createWithTransform = function(transform, serialized) {
  let settings = Settings.create(serialized);
  settings.transform = transform;
  return settings;
})

export default DS.ObservedTransform.extend({
  deserialize: function(serialized) {
    return Settings.createWithTransform(this, serialized);
  }
});

```

With all that, `user.get('settings').update('isAwesome', true)` should have the correct dirty/rollback behavior. Aside from the above could be sugarcoded more, does this work? All we need to do is to

1. add method `notifyObservedAttributeChanged` to `DS.Model`
2. change dirty tracking behavior

Does this sound doable?

---

<div class="post-metadata">

### Author: ![Senthe](https://avatars.discourse-cdn.com/v4/letter/s/c4cdca/32.png) [@Senthe](https://discuss.emberjs.com/u/Senthe)
#### Post date: [January 23, 2017, 9:05am UTC](https://discuss.emberjs.com/t/how-to-handle-object-array-attributes/7583/3 "2017-01-23T09:05:34Z")

</div>

I am still really interested whether the above post works or not.

(I think Ember Data seriously needs some native way to handle arrays and objects. You don’t always want a model for everything.)

---

<div class="post-metadata">

### Author: ![danielspaniel](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/danielspaniel/32/16112_2.png) [@danielspaniel](https://discuss.emberjs.com/u/danielspaniel)
#### Post date: [February 22, 2017, 5:00am UTC](https://discuss.emberjs.com/t/how-to-handle-object-array-attributes/7583/4 "2017-02-22T05:00:15Z")

</div>

I wrote an add on [GitHub - danielspaniel/ember-data-change-tracker: extending ember data to track and rollback changes including objects and associations](https://github.com/danielspaniel/ember-data-change-tracker) that handles what you are looking for
