Martin Algesten
Martin Algesten

Reputation: 13620

How do I observe *all* property changes on a model object?

I have a model built from a JSON object.

// extend the json model to get all props
App.Model = Ember.Object.extend(window.jsonModel);

I want to automatically save the model when anything is updated. Is there any way I can add an observer to the whole model?

EDIT: // adding the solution I currently go

For now I do:

// XXX Can't be right
for (var prop in window.jsonModel) {
    if (window.jsonModel.hasOwnProperty(prop)) {
        App.model.addObserver(prop, scheduleSave);
    }
}

This is a large form, which means I'm adding tons of observers – it seems so inefficient.

A firebug breakpoint at Ember.sendEvent() reveals that there are events called App.model.lastName:change being sent. I could hack in an intercept there, but was hoping for an official way.

Upvotes: 16

Views: 8942

Answers (4)

aceofspades
aceofspades

Reputation: 7586

I created a virtual property _anyProperty that can be used as a dependent key:

import Ember from 'ember';

Ember.Object.reopen({

  // Virtual property for dependencies on any property changing
  _anyPropertyName: '_anyProperty',
  _anyProperty: null,

  propertyWillChange(keyName) {
    if (keyName !== this._anyPropertyName) {
      this._super(this._anyPropertyName);
    }
    return this._super(keyName);
  },

  propertyDidChange(keyName) {
    if (keyName !== this._anyPropertyName) {
      this._super(this._anyPropertyName);
    }
    return this._super(keyName);
  }

});

Upvotes: 0

Shimon Rachlenko
Shimon Rachlenko

Reputation: 5517

You can bind to isDirty property of subclass of DS.Model. The isDirty changes from false to true when one of model properties changes. It will not serve well for all cases because it changes only once until reset or committed, but for your case -

I want to automatically save the model when anything is updated. Is there any way I can add an observer to the whole model?

it may work fine.

Upvotes: 8

Fordi
Fordi

Reputation: 2876

I had the same requirement, and not finding a suitable answer, I implemented one.

Try this: https://gist.github.com/4279559

Essentially, the object you want to observe all the properties of MUST be a mixed of Ember.Stalkable. You can observe the properties of that object as 'item.@properties' (or, if you bake observers directly on the Stalkable, '@properties' alone works. "@ownProperties", "@initProperties" and "@prototypeProperties" also work, and refer to (properties that are unique to an instance and not defined on any prototype), (properties that are defined as part of the create() invocation), and (properties that are defined as part of the class definition).

In your observers, if you want to know what properties changed and invoked the handler, the property "modifiedProperties", an array, will be available with the names of the changed properties.

Upvotes: 2

MattK
MattK

Reputation: 1531

From the article:

autosave: function(){
    this.save();
}.observes('attributes'),


save: function(){
  var self = this,
    url = this.get('isNew') ? '/todos.json' : '/todos/'+this.get('id')+'.json',
    method = this.get('isNew') ? 'POST' : 'PUT';

  $.ajax(url, {
    type: 'POST',
    // _method is used by Rails to spoof HTTP methods not supported by all browsers
    data: { todo: this.get('attributes'), _method: method },
    // Sometimes Rails returns an empty string that blows up as JSON
    dataType: 'text',
    success: function(data, response) {
      data = $.trim(data);
      if (data) { data = JSON.parse(data); }
      if (self.get('isNew')) { self.set('id', data['todo']['id']); }
    }
  });
},

isNew: function(){
   return !this.get('id');
}.property('id').cacheable(),

Upvotes: 2

Related Questions