77

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

Mobiletainment
  • 22,201
  • 9
  • 82
  • 98

13 Answers13

112

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}}
Pablo
  • 1,953
  • 4
  • 28
  • 57
Mobiletainment
  • 22,201
  • 9
  • 82
  • 98
11

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}}
Priyanshu Chauhan
  • 5,297
  • 5
  • 35
  • 34
8

I believe you can use...

{{math @index "+" 1}}
Adam Youngers
  • 6,421
  • 7
  • 38
  • 50
5

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}}
masterwok
  • 4,868
  • 4
  • 34
  • 41
4

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")

Max
  • 119
  • 1
  • 8
3

Throwing my solution in here. CSS counters.

body {
  counter-reset: section;                     /* Set a counter named 'section', and its initial value is 0. */
}

h3::before {
  counter-increment: section;                 /* Increment the value of section counter by 1 */
  content: counter(section);                  /* Display the value of section counter */
}

I was stuck on this and it was a nicer solution compared to adding a new helper.

SpaceBeers
  • 13,617
  • 6
  • 47
  • 61
3

for more accuracy in devlopment server use this

var hbs=require('express-handlebars')

var app = express();

app.set('view engine', 'hbs');

app.engine('hbs', hbs({
    helpers: {
        inc: function (value, options) {
            return parseInt(value) + 1;
        }
    },
    extname: 'hbs',
    defaultLayout: 'layout',
    layoutsDIR: __dirname + '/views/layout/',
    partialsDIR: __dirname + '/views/partials/'
}))

this part create a function called inc for increasing the value of {{@index}} by one

app.engine('hbs', hbs({

    helpers: {

        inc: function (value, options) {

            return parseInt(value) + 1;

        }
    },

we can use inc function with {{@index}} like this {{inc @index}}

here i include a screenshot of one of my project hosted in glitch.com and the link is given below

https://library-management-system-joel.glitch.me/view-books

(this project is under construction)

here i include a screenshot of one of my project hosted in glitch.com and the link is given below

thanks to Mobiletainment and Drkawashima

Joel
  • 31
  • 1
  • 4
1

The handlebars-helpers library has a fairly thorough mathematics library in lib/math.js, including a general purpose {{add a b}} helper defined as follows:

/**
 * Return the product of a plus b.
 *
 * @param {Number} a
 * @param {Number} b
 * @api public
 */
helpers.add = function(a, b) {
  return a + b;
};

If you don't want to copy and paste this into your project and you have the possibility to use npm, you can get this dependency as follows:

npm install handlebars-helpers --save

Then, you can register the math helpers as follows:

const handlebars = require('handlebars'),
  handlebarsHelpers = require('handlebars-helpers');

handlebarsHelpers.math({
  handlebars: handlebars
});
Pierre Spring
  • 10,525
  • 13
  • 49
  • 44
1

I was using nodejs and express-handlebars as template engine and facing same problem. And this is how I managed to solve.

You can create a folder and a js file inside it where you can create your own custom helpers that takes index and returns incrementing it by 1.

module.exports = {
    formatIndex: function(index)  {
        return index+1;
    }
}

Remember to register helper in your application(in my case app.js). I have used express-handlebars so I have reistered helper in this way:

app.engine('handlebars', exphbs({defaultLayout: 'home', helpers: { formatIndex }}));

Note: You have to import formatIndex before registering.

Then you can use it in your view as:

{{#each assignments}}
     <div>{{formatIndex @index }}</div>
{{/if}}
John
  • 972
  • 1
  • 7
  • 24
0

Create method eval

 Handlebars.registerHelper('eval', function(...e)
 {      
   e.pop();
   const args = e.join('');
        return eval(args)  ;
    }
 );

and use in any math actions

   {{eval @index " + 1"}}

or

   {{eval @index " + 1 - 2 * 4"}}

or

   {{eval @index " + 1" "- 2" "* 4"}}
Gopard
  • 922
  • 1
  • 12
  • 26
0

I refer in Helpers of express-handlebars document.

https://www.npmjs.com/package/express-handlebars

-----index.js-----

app.engine(
'hbs',
engine({
    extname: '.hbs',
    helpers: {
        sum: (a, b) => a + b,
    },
}),
);

-----handlebars file-----

<tbody>
        {{#each courses}}
        <tr>
            <th scope="row">{{sum @index 1}}</th>
            <td>{{this.name}}</td>
            <td>{{this.description}}</td>
            <td>{{this.createdAt}}</td>
        </tr>
        {{/each}}
    </tbody>

enter image description here

cng.buff
  • 405
  • 4
  • 5
0

I usually use this.

{{add @index 1}}

There is no helper needed, just increment +1 index from zero.

Item number {{add @index 1}}
Ilma A
  • 19
  • 1
-1

there is an easy way to incitement with the {{@index}} value.

solution is to call the funtion and pass the @index value o it and than on JS, use helper to return @index + 1

here is go

{{incitement @index}}

and here is code for the js

Handlebars.registerHelper("incitement", function (inindex) {
  return inindex + 1
});