Well, not so hidden to be honest, most of it is actually right there in the docs. And I still haven’t heard anyone call it the loopedy-loop helper – but it would be really fun if we all did! Other than that this post is 100% true and accurate.

Update December 8, 2014: This article has been updated to use Ember 1.8.1, the latest stable version at the time of writing. It’s also worth noting that Ember 2.0 will simplify a lot of these concepts by removing ArrayController and ObjectController and prevent you from using the context-switching form of {{each}}. Read more about this in The Road to Ember 2.0.

each in a nutshell

Given that our current controller is an ArrayController, this is each in it’s simplest form:

{{#each}}
  ...
{{/each}}

You’ve probably already written code like that a million times, or at least 20. In this example, the code above results in same thing as writing any of these:

  • {{#each controller}} – Since ArrayController proxies “itself” to content
  • {{#each this}} – In this case, this refers to the current controller
  • {{#each model}} – This is where the contents really are (most of the time)
  • {{#each content}}content is an alias for model (source)

As pointed out by @alexspeller in the comments, {{#each}}, {{#each controller}} and {{#each this}} iterates your controller, {{#each content}} and {{#each model}} iterates your content.

This can have very different results if the controller is an ArrayController which has an itemController specified.

Also, as Dom Christie writes, when you’re using sortProperties/sortAscending with ArrayController you need to access arrangedContent instead of content.

A demonstration of the above can be seen at http://emberjs.jsbin.com/serih/1/edit

What’s good to note is that all of these sets the context/this to the current item in our loop. So, if our content is an array of items with a foo property, we would access it like this:

{{#each}}
  {{foo}} ({{this.foo}} works too, if that's your cup of tea)
{{/each}}

U Can’t Touch This

But, what if we’ve got nested loops and don’t want to change this? We might want to be able to access items higher up the loop hierarchy? No sweat, we can prevent setting this to the current item in our loop by giving it an alias:

{{#each item in model}}
  {{#each child in item.children}}
    {{item.foo}} / {{child.foo}}
  {{/each}}
{{/each}}

Now, if our controller also has a property named foo, we’ll be able to write {{foo}} anywhere in the template above to get the value of our controller’s foo property since we’ve aliased our loop’s items to item and child and each was nice enough to leave this alone.

Note: To get ready for Ember 2.0 and make migration as easy as possible you should always use the non-context-switching form of each shown above.

No items for you!

When looping and displaying items to your users you most likely want to show a nice little message when there’s nothing to show. At first glance that would be easily solved with an if:

{{#if model}}
  {{#each item in model}}
    Item: {{item}}
  {{/each}}
{{else}}
  There are no items to show!
{{/if}}

But there’s an easier way, each has got you covered. No need for that pesky if as you can just put your else directly together with each:

{{#each item in model}}
  Item: {{item}}
{{else}}
  There are no items to show!
{{/each}}

Beautiful, isn’t it?

itemController and itemView

Another really great feature of each is the option to pass itemController and itemView. If we pass itemController to our each Ember will make sure that every item in your loop gets their own instance of the specified controller:

{{#each itemController='item'}}
  {{name}}
{{/each}}

By passing itemView to our each we make Ember rely on the layoutName (or template) defined in our view and use the shorter, non-block, version of each:

{{each itemView='item'}}

We could use itemViewClass='App.ItemView' too but using itemView makes Ember lookup the view in the container instead of us having to specify the full path.

Research has shown that itemController and itemView can be combined too. Great success.

Different different, but same

It’s a common thing to loop over an array of items and render a separate template for each item. It’s also quite common that you want each of those items to have their own instance of a controller and view. This can be acheived in multiple ways.

Let’s start with some prerequisites, shall we? Imagine this JavaScript code:

App.IndexRoute = Ember.Route.extend({
  model: function() {
    return [
      { name: 'Peter' },
      { name: 'Lois' },
      { name: 'Brian' }
    ];
  }
});

App.ItemController = Ember.ObjectController.extend({
});

App.ItemView = Ember.View.extend({
  layoutName: 'item'
});

And combine it with this extremely sophisticated template, named item:

{{name}}

With this in place we can now use any of the following variants to achieve the same result in our application. A list of items, all rendered with the item template, having their own instances of ItemController and ItemView:

1. each + render

{{#each}}
  {{render 'item' this}}
{{/each}}

2. each with itemController and itemView

{{each itemController='item' itemView='item'}}

3. each with itemController + view

{{#each itemController='item'}}
  {{view 'item'}}
{{/each}}

There are some minor differences in all of these, but fortunately nothing that can’t be handled:

  1. If we’d try to access this.controller in our ItemView, #3 would give us undefined. this.get('controller') works.
  2. And if we’d try to access this.get('model') (or this.get('model.name')), #1 and #3 would give us undefined. Use this.get('context') (or this.get('context.name')) instead.

Here’s a working JS Bin demonstrating the different variants above: http://emberjs.jsbin.com/gifog/3/edit

All good things must come to an end

There’s a lot to learn about each and being able to know when to use it how will hopefully make you feel even more at home with Ember. There’s a lot of great stuff to learn by reading the docs and the Ember source code – who needs books?

I’ll be happy as a kid on Christmas if you leave a comment, and don’t forget to follow me on Twitter: @EmberGuru.

Confession

For the record, I’m blown away by this amazing community and all the great feedback I got for my first article, Master your modals in Ember.js. I could never have imagined such a great response. Thanks! :)

EmberFest

I’d also like to give a shout out to @EmberFest happening in Barcelona 26th – 29th of August. Book your tickets at emberfest.eu if you haven’t already. I hope to see you there!