copenndthagen
copenndthagen

Reputation: 50732

Ember observe nested model property

In EmberJS, if I want to observe a property "selectedValue" which is inside a nested model, how can I do that ?

The below does not seem to be working;

modelChanged: function() {  

}.observes('myModel.@[email protected]'),

Also the below does not work

modelChanged: function() {  

}.observes('myModel'),

This is how myModel looks like

[
    [{
        "prop1": "abc_1",
        "selectedValue": "abc_1"
    }, {
        "prop1": "xyz_1",
        "selectedValue": "xyz_1"
    }],
    [{
        "prop1": "abc_2",
        "selectedValue": "abc_2"
    }, {
        "prop1": "xyz_2",
        "selectedValue": "xyz_2"
    }],
    [{
        "prop1": "abc_3",
        "selectedValue": "abc_3"
    }, {
        "prop1": "xyz_1",
        "selectedValue": "xyz_1"
    }]
]

Update based on

Seems to be working...Just a couple of questions;

  1. In above code, "observedObjects" just adds for the first outer array and tracks property within this arr[0]. I have multiple outer array elements

    1. How can I modify the above to track for multiple properties ? i.e. In some cases, it would be "selectedValue" OR it can be "preSelectedValue" in other cases . What property it is would depend upon that object itself. But I need to track change of either selectedValue/preSelectedValue

    2. Also in observerMethod, can I get a context and check what the new selectedValue/preSelectedValue is?

Upvotes: 1

Views: 890

Answers (1)

maffews
maffews

Reputation: 525

What is the structure of your nested model? If myModel is an array of elements with selectedValue, you can use [email protected]. If you need multiple levels of nesting, that's not supported out of the box.

From the documentation:

Note that @each only works one level deep. You cannot use nested forms like [email protected] or [email protected][email protected].

There are workarounds that depend on your model structure, and if you reply or update the question with your structure I'll update my answer to cover an appropriate solution.

Update: Depending on how myModel is set/updated, you may need to adjust when observeMyModelChildren is called and how it creates observers.

// observerMethod is called when myModel.@[email protected] changes
observerMethod: function () {
  // handle change
},

// observedObjects tracks child observers so they can be removed
observedObjects: [],

// observeMyModelChildren listens for changes to myModel, removes 
// old observers, and adds new ones 
observeMyModelChildren: function () {
  const key = '@each.selectedValue';

  this.get('observedObjects').forEach((el) => {
    el.removeObserver(key, this, this.observerMethod);
  });
  this.set('observedObjects', []);

  let observedObjects = [];
  this.get('myModel').forEach((el) => {
    el.addObserver(key, this, this.observerMethod);
    observedObjects.pushObject(el);
  });
  this.set('observedObjects', observedObjects);
}.observes('myModel'),

Update 2: If you want to support observing multiple properties (e.g. other models), you can do do that by modifying observeMyModelChildren:

observePropertyChildren: function (obj, attr) {
  console.log('setting up observers on', attr);

  var key = 'observedObjects.' + attr;
  var observedObjects = this.get(key) || [];
  observedObjects.forEach((el) => {
    el.removeObserver('@each.selectedValue', this, this.observerMethod);
  });

  this.get(attr).forEach((el) => {
    el.addObserver('@each.selectedValue', this, this.observerMethod);
    observedObjects.pushObject(el);
  });
  this.set(key, observedObjects);
}.observes('myModel', 'myOtherModel'),

Upvotes: 1

Related Questions