Nested #each doesn't seem to work


#1

I have a view with a datastructure like this:

columnsData: [ this.columnData1, this.columnData2],
columnData1: [ {"name" : "John"}, {"name": "Tony"},
columnData2: [ {"name": "Sara"}, {"name": "Amanda"}

in my .hbs for this view i’d like to do:

{{#each column in view.columnsData}}
  <div class="column">
      {{#each item in column}}
           <div class="item">
                {{item.name}}
           </div>
      {{/each}}
   </div>
{{/each}}

This never seems to execute on the inner each. I’ve read online peple saying to put {{#each this}} but the “this” is my controller then :wink:

Thoughts :)?

This seems like the most trivial use case, so baffled it won’t work.

EDIT: Okay - so this is just a javascript error thing I believe. if I cut and paste the arrays INTO columnsData vs using the “this” reference… it all works. i.e.

columnsData: [ [a,b], [c,d] ] appears to work.

Hrm!


#2

Can you post the entire view code? I suspect the problem is the way you’re trying to populate columnsData.


#3

Not exactly sure what more you want to see.

From my little test bed, that was literally a cut and paste of the .js view code and the .hbs template file.

somehow the columnsData: [ this.columnData1, this.columnData2], fails because “this” isn’t right… somehow… haha

I was just hard coding stuff in to test something out.


#4

Ok, so it sounds like you have something like this?

var MyView = Ember.View.extend({
  columnsData: [this.columnData1, this.columnData2],
  columnData1: [ {"name" : "John"}, {"name": "Tony"} ],
  columnData2: [ {"name": "Sara"}, {"name": "Amanda"} ]
})

If so, the reason this isn’t working is because when columnsData is set, this does not refer to the view. There are a few ways you could fix this. One is to set it up in init:

var MyView = Ember.View.extend({
  // Note, setting these to null isn't actually
  // necessary—I just like it so I know what data
  // there is
  columnsData: null,
  columnData1: null,
  columnData2: null,

  init: function() {
    this._super();

    this.set('columnData1', [ {"name" : "John"}, {"name": "Tony"} ]);
    this.set('columnData2', [ {"name": "Sara"}, {"name": "Amanda"} ]);
    this.set('columnsData', [this.get('columnData1'), this.get('columnData2')])
  }
})

What happens here is when the view is created, it runs init and then sets all the appropriate properties. Since init is run in the context of the view instance, you can refer to other properties in it. Also, you might notice I set up columnData1 and columnData2 in init as well. Check out this blog post under “Initialization (and a common mistake!)” for info on why that’s a good idea.

Another way to do this is with computed properties:

var MyView = Ember.View.extend({
  columnData1: null,
  columnData2: null,

  init: function() {
    this._super();

    this.set('columnData1', [ {"name" : "John"}, {"name": "Tony"} ]);
    this.set('columnData2', [ {"name": "Sara"}, {"name": "Amanda"} ]);
  },

  columnsData: function() {
    return [this.get('columnData1'), this.get('columnData2')]
  }.property('columnData1.[]', 'columnData2.[]')
})

Now, whenever columnData1 or columnData2 changes, columnsData is automatically updated.

Also important to note: you should be using get and set for accessing values on your objects—this allows a lot of the Ember magic to take place (like computed properties).


#5

Yeah… it was just the simple javascript mistake of “this” at instantiation time…

I use get and set in other places (in real code) and I use computed properties all the time.

I was just trying in haste to fake some data to test out nested each statements and stepped off on the wrong foot hah!

Thanks for your great response!