Adding offset to {{@index}} when looping through items in Handlebars

I'm iterating over a list in Handlebars using the built-in each helper. Within the each block, I'm referencing the current loop index {{@index}} to print the consecutive number of an item:

<script id="list-item-template" type="text/x-handlebars-template">
    {{#each items}}
    <li class="topcoat-list__item">
        <a href="#{{@index}}">Item number {{@index}}</a>
    </li>
    {{/each}}
</script>

This gives the following output:

  • Item number 0
  • Item number 1
  • Item number 2
  • ....

The problem is that I want to display an offsetted index which starts with 1 instead of 0.

I tried to perform calculations on the index like {{@index+1}}, but this just leads to an

Uncaught Error: Parse error


Solution 1:

Handlebars gives you the possibility to write a custom helper that handles this situation, e.g. a helper function that lets you perform calculations on expressions like addition and subtraction etc.

Below function registers a new helper, which simply increments a value by 1:

var Handlebars = require('handlebars');

Handlebars.registerHelper("inc", function(value, options)
{
    return parseInt(value) + 1;
});

You can then use it within the handlebar expression using the inc keyword, like:

{{inc @index}}

Solution 2:

Actual answer: https://stackoverflow.com/a/46317662/1549191

Register a math handlebar and perform all mathematical operations.

app.engine('handlebars', exphbs({
  helpers:{
    // Function to do basic mathematical operation in handlebar
    math: function(lvalue, operator, rvalue) {lvalue = parseFloat(lvalue);
        rvalue = parseFloat(rvalue);
        return {
            "+": lvalue + rvalue,
            "-": lvalue - rvalue,
            "*": lvalue * rvalue,
            "/": lvalue / rvalue,
            "%": lvalue % rvalue
        }[operator];
    }
}}));
app.set('view engine', 'handlebars');

Then you can directly perform operation in your view.

    {{#each myArray}}
        <span>{{math @index "+" 1}}</span>
    {{/each}}

Solution 3:

I believe you can use...

{{math @index "+" 1}}

Solution 4:

To expand on Mobiletainment's answer, this solution allows for the value to be incremented by to be passed in as an argument. If no value is passed, then a default value of 1 is used.

Handlebars.registerHelper('inc', function(number, options) {
    if(typeof(number) === 'undefined' || number === null)
        return null;

    // Increment by inc parameter if it exists or just by one
    return number + (options.hash.inc || 1);
});

Within your template you can then write:

{{inc @index inc=2}}

Solution 5:

I solved this issue for myself by adding a short script tag to the bottom of my handlebars code!

Add a class to wherever you are calling @index and then the below jQuery code works (can also be done using vanilla JS).

<p class="create_index">
     {{@index}}
</p>
<script>
    $(".create_index").text(parseInt($(".create_index").text())+1)
</script>

edit 4/28- This has changed to use vanilla JS for better backwards compatibility (i.e. IE7, 8):

<span class="create_index"></span>
<script>
    var divs = document.querySelectorAll('.create_index');
    for (var i = 0; i < divs.length; ++i) {
        divs[i].innerHTML = i + 1;
    }
</script>

document.querySelectorAll has great compatibility but could also be document.getElementsByClassName("create_index")