How to make removeObject KVO-compliant?


#1

I have model

import DS from 'ember-data';

export default DS.Model.extend({
	Structure: DS.attr('raw'),
});

So, structure is array of objects

[{
    type: 'comp-a',
    children: [
        {type: 'comp-b'},
        {type: 'comp-b'}
    ]
}]

Next, i print this structure

structure: Ember.computed('model.Structure', function() {
    var st = this.get('model.Structure');
    // handle this structure

    return st;
});
{{#each structure as |item|}}
	{{component item.type}}
{{/each}}

Question. When I push object to comp-a, Ember renders new pushed component

this.get('model.Structure')[0].children.pushObject({
    type: 'comp-b'
});

But, when I remove any object it doesn’t.

var child = this.get('model.Structure')[0].children[0];
this.get('model.Structure')[0].children.removeObject(child);

#2

You need to add the children array to your computed properties list of dependent keys.

From:

To:

structure: Ember.computed('model.Structure', 'model.Structure.children.[]', function() {
    var st = this.get('model.Structure');
    // handle this structure

    return st;
});

#3

Ok thanks. But Structure is dynamic and I don’t know the depth of children beforehand.


#4

Because you’re needing to observe at an arbitrary depth — you’ll either want to have a component for each of those levels that can set up the computed property for each of the child arrays, or perhaps use a helper of some sort inside your {{#each}} helper.

For example, if you take this helper (a bit inspired by ember-composable-helpers ) – it is going to set up an observer on the array and watch for any push/removes performed on the array and return a new array instance every time something changes.

// helpers/observe-array.js
import Ember from 'ember';

export default Ember.Helper.extend({
  compute([array]) {
    this.set('array', array);
    return Ember.A(array.slice(0));
  },

  arrayContentDidChange: Ember.observer('array.[]', function() {
    this.recompute();
  })
});

Then, your template would get updated like so:

{{#each (observe-array structure) as |item|}}
  {{component item.type}}
{{/each}}

…then…that should “just work” given how it seems you’re handling everything else right now.