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