Skip to content

Embed URL

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
each_with_index handlebars helper, adds an {{index}} prop accessible from within the block
Handlebars.registerHelper 'each_with_index', (array, fn) ->
buffer = ''
for i in array
item = i
item.index = _i
buffer += fn(item)
buffer
// {{#each_with_index records}}
// <li class="legend_item{{index}}"><span></span>{{Name}}</li>
// {{/each_with_index}}
Handlebars.registerHelper("each_with_index", function(array, fn) {
var buffer = "";
for (var i = 0, j = array.length; i < j; i++) {
var item = array[i];
// stick an index property onto the item, starting with 1, may make configurable later
item.index = i+1;
// show the inside of the block
buffer += fn(item);
}
// return the finished buffer
return buffer;
});
@logankoester

Or as CoffeeScript...

Handlebars.registerHelper 'each_with_index', (array, fn) ->
  buffer = ''
  for i in array
    item = i
    item.index = _i
    buffer += fn(item)
  buffer
@burin
Owner

thanks logan! added it to the gist :)

@Phylodome

A more generalized/flexible approach to this would be:

Handlebars.registerHelper 'eachWithFn', (items, opts) ->
    _(items).map((item, i, items) =>
        opts.hash.fn.apply opts, [item, i, items]
        opts.fn(item)
    ).join("")

You can then pass an arbitrary function in the context such as:

ctx=
    items: items 
    fn: (item, i, items) ->
        item.index = if not @hash.zeroIndexed then i + 1 else i

In the template this would look something like:

{{#eachWithFn items fn=fn zeroIndexed=false}}
    <p>{{index}}</p>
{{/eachWithFn}}

If you're going to create a helper, it's ill advised to implement a one-off where a more generally applicable solution exists. Imagine having a helper for each kind of list manipulation you'd want to perform. Definite code creep.

Edit: This code relies on the underscore.js library, but jQuery's map would work similarly.

@willywongi

I would use an array instead of a string concatenation (see my fork of this gist).

@zedtux

I tried it in a Rails 3.2 application with handlebars_assets 0.6.6.

I just copied/pasted the coffeescript version and use it in my template, but when rendering the template, Firebug catch the following Javascript error:

TypeError: fn is not a function
buffer += fn(item);

Could you please confirm me that it's working on your machine ?

@buley

The error message is quite accurate in this case. The second callback isn't a function, it's an object. Try this:

      Handlebars.registerHelper 'each_with_index', (array, obj) ->
        buffer = ''
        for i in array
          item = i
          item.index = _i
          buffer += obj.fn(item)
        buffer          
@mlienau

I was getting the same error using handlebars-1.0.rc.1.js. The following is the solution I came up with. I like the zero based index better

Handlebars.registerHelper("each_with_index", function (array, data) {
// "array" is the name of the array you want to iterate over
array = data.contexts[0][array];

    var buffer = "";
    for (var i = 0, j = array.length; i < j; i++) {
        var item = array[i];

        // if item is already an object just add the index property
        if (typeof (item) == 'object') {
            item['index'] = i;
        } else { // make an object and add the index property
            item = {
                value: item, // TODO: make the name of the item configurable
                index: i
            };
        }

        buffer += data.fn(item);
    }

    // return the finished buffer
    return buffer;

});
@mlienau
Handlebars.registerHelper("each_with_index", function (array, data) {

    array = data.contexts[0][array];

    var buffer = "";
    for (var i = 0, j = array.length; i < j; i++) {
        var item = array[i];

        // if item is already an object just add the index property
        if (typeof (item) == 'object') {
            item['index'] = i;
        } else { // make an object and add the index property
            item = {
                value: item, // TODO: make the name of the item configurable
                index: i
            };
        }

        buffer += data.fn(item);
    }

    // return the finished buffer
    return buffer;
});
@rxaviers

For node:

Handlebars.registerHelper( "join", function( array, sep, options ) {
    return array.map(function( item ) {
        return options.fn( item );
    }).join( sep );
});
<p>
    {{#join companies "<br>"}}
        {{name}}
    {{/join}}
</p>
@Hypher

I don't think it's a good idea to alter template data adding an 'index' ppty to iterated elements. This can be a nasty side effect. Handlebars allow to define custom variables through options.data and createFrame

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.