Each {{#each}} with index

Getting a little frustrated with this…

Can someone give me a clear and simple example of how we should go about getting the index of items within an {{#each}} loop?

Yes, I’ve seen this StackOverflow post, but it doesn’t seem to solve my problem. Specifically, I’m trying to use the index in a class name.

What I’m seeing now is something like:

<li class="item-<script id='metamorph'>...</script>">Item 1</li>

What I actually want is:

<li class="item-1>Item 1</li>

Am I missing something? I feel like this should be built into Ember?

You can use the index in a class name using the {{bindAttr}} helper as described here.

I went ahead and wrote a quick example based off that SO post, too: Ember Latest - JSFiddle - Code Playground

When you use {{#each content}} Ember will default to use a “virtual view”. If you use {{#each content itemClassView="App.ItemView"}} your items will be “concrete views” instead. Concrete views, when a child of an Ember.CollectionView (which is what #each uses internally), gets a contentIndex property set automatically.

You can use this contentIndex to style your elements.

Here is a working fiddle: Ember Latest - JSFiddle - Code Playground

8 Likes

Thanks @thomasboyt and @seilund. I really appreciate the responses, especially for going through the trouble of putting together a JSFiddle. I’ll be using these techniques in my code for sure.

This being said, I’m looking forward to the day when {{#each}} has an easier way to access indexes. It’s such a common requirement that these solutions all feel too heavy.

1 Like

Would you expect the itemClassView specified in the {{#each}} to be able to specify its own template? As far as I can tell, the itemView ignores the templateName property when you hook things up like this: Ember Latest - JSFiddle - Code Playground

Is this a case where you’re better off building a CollectionView rather than using {{#each}}?

You can use the non-block version of {{each}}. Like thise: Ember Latest - JSFiddle - Code Playground

3 Likes

Very helpful, thanks.

what is your intention with getting the index? Is it to “cycle” through class assignments while going through the loop (cos I can’t imagine you somehow styling <li>s specifically by their number?), like how the Rails cycle helper works (ActionView::Helpers::TextHelper)? That would be my own use case for this - and I imagine that most folks’ reason for getting the index would be to do the same.

So I could imagine something like this:

<li {{ bindAttr class='cycle( grey, white )' }}>{{ name }}</li>

Or even as part of the {{linkTo}}:

{{#linkTo user user class='cycle( grey, white )'}}{{ user.name }}{{/linkTo}}

I think having something like this built into Ember would make sense.

1 Like

I was trying to build out a responsive grid style layout and needed the ability to target specific items and alter CSS properties depending on the viewport width. I was able to get this working using @seilund’s example, but then rewrote it using Selectivizer and nth-child() properties.

Although I understand this is a hard problem, I still find it problematic that this is not easier. Just makes it a tough sell with my work friends.

Exactly what I was looking for. If you guys want to make the index 1-based for display purposes you can use incrementProperty.

this.incrementProperty('contentIndex');

Hopefully, this is built into the core at some point. I need this sort of thing most of the time for styling.

…or use a computed property:

oneBasedContentIndex: function() {
  return 1 + this.get('contentIndex');
}.property('contentIndex');