2

When setting property observable on a nested array in ember my property isn't notified.

size: function(){
      var result = "no size";

      this.get('data.properties').forEach(function (g) {
        if (g.group == "style") {
            g.items.forEach(function (p) {
                if (p.id == 'size') result = p.computedValue();
            });
        }
      });

    console.log(result);

    return result;
}.property('[email protected][email protected]')

In this SO accepted answer : https://stackoverflow.com/a/9381152/2068563 it says that this should work.

But for me the propurty is only computed at init. here is the fiddle: http://jsfiddle.net/jmorvan/eVWfj/

Any ideas?

1 Answer 1

1

Ok so, the solution is to link computed properties updated by observable to bubble up the event like this:

App.groupObj = Ember.Object.extend({
    group: "style",
    name: "Style",
    _changed: 0,
    changed: function (key, value) {
        if (value) {
            this.set('_changed', value);
        }
        return this.get('_changed');
    }.property(),
    itemChanged: function () {
        this.set('changed', +new Date());
        console.log('item changed!');
    }.observes('[email protected]'),

    items: []
});

App.itemObj = Ember.Object.extend({
    _val: 6,
    id: null,
    name: null,
    group: null,
    fieldType: null,
    val: function (key, value) {
        if (value) {
            this.set('_val', value);
        }

        return this.get('_val');
    }.property(),
    computedValue: function () {
        return this.val;
    }
});

Basically, the grouo object listens to any action on the item's val property and updates his own changed property. this way i can do:

size: function(){
      var result = "no size";

      this.get('data.properties').forEach(function (g) {
        if (g.group == "style") {
            g.items.forEach(function (p) {
                if (p.id == 'size') result = p.computedValue();
            });
        }
      });

    console.log(result);

    return result;
}.property('[email protected]')

I guess my first miastake was to think ember was magically going to pickup changes on my nested objects.

I also thought that linking computed properties would work, which obviously didnt! (Why?)

the updated fiddle: http://jsfiddle.net/jmorvan/LEyCD/

EDIT

Since this was pretty long to implement on each object I created my own object with observable based on a selector.

    App.changeAwareArray = Ember.ArrayProxy.extend({
    init: function () {

        this.set('content', []);
        this._super();
        if (!this.get('changeSelector')) this.set('changeSelector', '_changed');

        this.addObserver('content.@each.' + this.get('changeSelector'), this.handleChange);
    },
        _changed: null,
    handleChange: function () {
        this.set('_changed', +new Date());
    }
});

App.changeAwareObject = Ember.Object.extend({
init: function () {
        this._super();
        if (!this.get('changeSelector')) this.set('changeSelector', '_changed');

        this.addObserver(this.get('changeSelector'), this.handleChange);
    },
        _changed: null,
    changed: function (key, value) {
        if (value) {
            this.set('_changed', value);
        }
        return this.get('_changed');
    }.property(),
    handleChange: function () {
        this.set('_changed', +new Date());
    }
});

Now you can chain them to observe them:

    App.groupObj = App.changeAwareObject.extend({
    changeSelector:'items._changed',
    group: "style",
    name: "Style",
    items: App.changeAwareArray.create()
});

App.itemObj = Ember.Object.extend({
    _val: 6,
    _changed: null,
    id: null,
    name: null,
    group: null,
    fieldType: null,
    val: function (key, value) {
        if (value) {
            this.set('_val', value);
            this.set('_changed', +new Date());
        }
        return this.get('_val');
    }.property(),
    computedValue: function () {
        return this.val;
    }
});

And get the data in your view/controller:

    App.IndexView = Ember.View.extend({
    init: function () {
        this._super();
        //populate the Array
        this.data.properties.pushObject(createData());
    },
    elementId: "test",
    size: function () {
        var result = "no size";

        this.get('data.properties').forEach(function (g) {
            if (g.group == "style") {
                g.items.forEach(function (p) {
                    if (p.id == 'size') result = p.computedValue();
                });
            }
        });

        return result;
    }.property('data.properties._changed'),
    offset: function () {
        var result = "no offset";

        this.get('data.properties').forEach(function (g) {
            if (g.group == "style") {
                g.items.forEach(function (p) {
                    if (p.id == 'offset') result = p.computedValue();
                });
            }
        });

        return result;
    }.property('data.properties._changed'),
    data:{
        name: "base",
        properties: App.changeAwareArray.create()
    }
});

you can find a working fiddle here: http://jsfiddle.net/jmorvan/VRVac/

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.