Skip to main content

Iteration variables

Inside a loop block, four Handlebars-style @-prefixed variables expose the iteration state:

VariableTypeMeaning
{{@index}}numberZero-based index of the current iteration
{{@key}}numberSame as @index for arrays (kept for Handlebars parity)
{{@first}}booleantrue on the first iteration, false otherwise
{{@last}}booleantrue on the last iteration, false otherwise

Outside a loop, all of these resolve to undefined (and render as empty strings).

Example: rendering a comma-separated list

{{#items}}{{#if @first}}[{{/if}}{{@index}}:{{$this}}{{#if @last}}]{{else}}, {{/if}}{{/items}}

With context { "items": ["a", "b", "c"] } the output is [0:a, 1:b, 2:c].

Example: alternating row classes

{{#each rows}}
<tr class="{{#if @first}}first {{/if}}{{#if @last}}last{{/if}}">
<td>{{@index}}</td>
<td>{{name}}</td>
</tr>
{{/each}}

Nesting

When loops are nested, the inner iteration shadows the outer one. The inner block sees its own @index / @first / @last; the outer values are not directly reachable.

{{#each groups}}
Group
{{@index}}:
{{name}}
{{#each items}}
{{@index}}.
{{$this}}
{{/each}}
{{/each}}

There is no @../index syntax to reach the outer loop's index. The cleanest way to keep it is block params, which name the outer index so the inner body can read it directly:

{{#each groups as |group g|}}
{{#each group.items as |item i|}}
Outer
{{g}}, inner
{{i}}:
{{item}}
{{/each}}
{{/each}}

Alternatively, capture it in a variable before entering the inner loop:

{{#each groups}}
{{= $groupIndex @index}}
Group {{@index}}: {{name}}
{{#each items}}
Outer {{$groupIndex}}, inner {{@index}}: {{$this}}
{{/each}}
{{/each}}

Why @key?

Handlebars uses @key for object iteration (where the key is a string) and @index for array iteration (where the key is a number). Bigodin does not iterate objects directly — there is no {{#each obj}} over an object's keys — so @key is exposed as an alias of @index purely for template portability.