Array in component is static instead of per instance, why?


#1

I have a component that contains sub components and can potentially be nested inside itself. I seem to be having a problem where the variable ‘panes[]’ appears to be static between all components when i would assume it would be an instance member.

For instance here is a sample of my code, when this runs the panes[] contains 4 elements instead of 2 and then 2. Why?

{{#splitter}}
     {{#pane}} content {{/pane}}
     {{#pane}}
         {{#splitter}}
               {{pane}}
               {{pane}}
         {{/splitter}}
     {{/pane}}
{{/splitter}

pane code:

export default Ember.Component.extend({
      addPaneToParent: function()
    {
        var parent = this.get('parentView');
        if(parent.registerChildPane)
        {
            parent.registerChildPane(this);
        }
    }.on('init'),
});

splitter code:

export default Ember.Component.extend({
    panes: [],
    didInsertElement: function() {
           var panes = this.get('panes');
    }
    registerChildPane: function(pane) {
        console.log(this.get('elementId') + ' ' + pane.get('elementId'));
        this.get('panes').addObject(pane);
    }
});

#2

So it appears i can make it an instance member by doing the following.

initializeArray: function(){
        this.set('panes', []);
    }.on('init'),

Why do i have to do this?


#3

Fundamentally, because that’s how Prototypal Inheritance works in JavaScript:

function MyClass() {
}

MyClass.prototype.anArray = [];

var instanceOne = new MyClass();
var instanceTwo = new MyClass();
instanceOne.anArray.push('from one');
instanceTwo.anArray; // [ 'from one' ]

Ember could solve this by doing a deep copy of the class prototype whenever you call .create(), but it would be extremely wasteful, memory-wise.

I often create a computed-property macro for empty arrays and objects:

import emptyArray from "my-app/utils/empty-array";

export default Ember.Component.extend({
  panes: emptyArray()
});

and

// empty-array.js:
import "Ember" from "ember";
export default Ember.computed(function() {
  return [];
});

I remember @ebryn once telling me there was a better way to write that macro, but I don’t remember what it was.