ArrayProxy content.length vs length


#1

I’m not sure I understand ArrayProxy.

I’m trying to extend ArrayProxy, and I’m using pushObject to add content to my array. I see the content getting updated, but for whatever reason the length of the array does not seem to accurately reflect the number of contents like I’d expect.

https://ember-twiddle.com/326feda37dd1e773c038f7f07885207c?openFiles=templates.application.hbs%2C

I feel like I’m probably missing something simple. The docs say ArrayProxy is a concrete implementation, but do I need to implement length myself?


#2

From what is given here, looks like you will have to implement the method


#3

Yeah, I saw that same section you reference in the docs. I assumed that it was just misleading/incorrect because the ArrayProxy length docs seem to be taken directly from the Array mixin docs, since ArrayProxy implements, Array.

It’s confusing because that section you reference conflicts (in my opinion) with these docs.

For example, ArrayProxy is a concrete classes that can be instantiated to implement array-like behavior.

I’d assume the concrete class would supply the functionality around length, but it seems like it does not. Or I’m just totally missing the point of the ArrayProxy or doing something wrong.


#4

Your twiddle seems to be not available. Can you update?


#5

Link updated up above and here: https://ember-twiddle.com/326feda37dd1e773c038f7f07885207c?openFiles=templates.application.hbs%2C


#6

Not sure why though, but specifying content while creating the arrayproxy seems to fix it. Updated twiddle:

https://ember-twiddle.com/0ca48580e37cfbbfec3d9c289aa670ac?openFiles=controllers.application.js%2C


#7

Thanks Akash. You’re totally right.

I’ve been getting the hint lately that it’s best to avoid overloading init when possible in Ember, and this is certainly another convincing point for me. It does seem a little unintuitive that they’d behave differently, but clearly there’s some sort of magic that happens if content is specified on create vs being set as a property in init.

For posterity for anyone reading this thread…

// Akash's suggestion which solves my problem.
CustomArray.create({content: []}));
// My initial implementation which does not work as expected.
CustomArray.create();
// CustomArray's init method.
...
  init() {
    this._super(...arguments);
    this.set('content', []);
  }
...

Interestingly, I found that if I change the order of operations in my init, that also fixes the issue.

  init() {
    this.set('content', []);
    this._super(...arguments);
  }

Which makes sense to me now. content must be specified before ArrayProxy’s init() is invoked.


#8

Yes! Initially content is null (https://github.com/emberjs/ember.js/blob/v2.12.0/packages/ember-runtime/lib/system/array_proxy.js#L84) Because of this, no observers will be sent on the array proxy https://github.com/emberjs/ember.js/blob/v2.12.0/packages/ember-runtime/lib/system/array_proxy.js#L196 Hence, even when content is changed, the changes were not observed