10

I am using handlebars.js templates with node and express. I am making a numbered list using the {{@index}} template tag, however since index starts at 0 and I want to start from one, it seems I need to use a custom helper. I've seen plenty of posts regarding this and I've found the following code:

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

{{#each score}}
      <li class="list-group-item">
      <div id="place"> {{inc @index}} &nbsp </div>
      <div class="wordOrName">{{ player_name }}</div>
           <div class="number">{{ score }}</div></li>
        {{/each}}

What I cannot seem to find is where the helper register function is supposed to go. I've tried putting it inside in the template itself and in various other places but I still keep getting

Error: Missing helper: "inc"
   at model.<anonymous>

Ideally I'd like to have the helper in a separate file helpers.js but I don't have the slightest idea of how to get handlebars to recognize it.

EDIT:

Handlebars is included in the project with the following code inside the node file index.js:

// view engine
app.set('views', __dirname + '/views/');
app.set('view engine', 'handlebars');
app.engine('handlebars', engines.handlebars); 

It appears impossible to include the helper function within the template itself.

Cameron Sima
  • 5,086
  • 6
  • 28
  • 47

6 Answers6

13

I figured it out...The helpers indeed need to be registered in the node app file like so:

// view engine
app.set('views', __dirname + '/views/');
app.set('view engine', 'handlebars');
var hbs = require('handlebars');
hbs.registerHelper("inc", function(value, options)
{
    return parseInt(value) + 1;
});
app.engine('handlebars', engines.handlebars);

I wish this info was more easily accessible, but there it is.

Cameron Sima
  • 5,086
  • 6
  • 28
  • 47
  • 1
    It is working in my development server,but not in production.And code is same.I tried the above code but didnt work. – SREE ANI Jun 03 '20 at 03:54
8

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}}
lance.dolan
  • 3,493
  • 27
  • 36
Priyanshu Chauhan
  • 5,297
  • 5
  • 35
  • 34
  • This works when using express-handlebars instead of handlebars. Thank you – Nimesha Kalinga May 21 '18 at 11:05
  • Or register '+' (lvalue, rvalue) => parseFloat(lvalue) + parseFloat(rvalue), and similar for '-', '*' and '/' if needed, and then use them as {{'+' @index 1}} if you dont need or want different operator implementations for different data types – johan mårtensson Dec 18 '18 at 15:14
3

You don't need to add require('handlebars') just to get helpers working. You can stick to express-handlebars. Define helpers in a config object like so var myConfig = { helpers: {x: function() {return "x";}} } and pass it to the express-handlebars-object like so: require('express-handlebars').create({myConfig})

Here's a fully functional example with some helpers and some view directories configured.

var express = require('express');
var exphbs = require('express-handlebars');
var app = express();
var hbs = exphbs.create({
    helpers: {
        test: function () { return "Lorem ipsum" },
        json: function (value, options) {
            return JSON.stringify(value);
        }
    },
    defaultLayout: 'main',
    partialsDir: ['views/partials/']
});
app.engine('handlebars', hbs.engine);
app.set('view engine', 'handlebars');
app.set('views', path.join(__dirname, 'views'));

My understanding is that the object returned from require('express-handlebars'); is not a "real" handlebars object. So you can't rely on some functions, and instead you have to pass stuff like helpers via a config object to the .create() function

Drkawashima
  • 8,837
  • 5
  • 41
  • 52
1

We can fix this issue with css counter property:

body {
  /* Set "my-sec-counter" to 0 */
  counter-reset: my-sec-counter;
}

h2::before {
  /* Increment "my-sec-counter" by 1 */
  counter-increment: my-sec-counter;
  content: counter(my-sec-counter) ". ";
}
<h2>HTML Tutorial</h2>
<h2>CSS Tutorial</h2>
<h2>JavaScript Tutorial</h2>
<h2>Bootstrap Tutorial</h2>
<h2>SQL Tutorial</h2>
<h2>PHP Tutorial</h2>
enzo
  • 9,861
  • 3
  • 15
  • 38
  • 1
    Can you add some explanation for what your code here is doing and how it pertains to Handlebars.js – Kaia Aug 12 '21 at 17:01
0

You could just paste the helpers inside a separate file, as you said something like "helper.js" and include it in your HTML page after you had imported Handlebars JS file.

<script src="handlebars.min.js"></script>
<script src="helper.js"></script>

You can also check out Swag (https://github.com/elving/swag) It contains a lot of helpful handlebar helpers.

raghav
  • 285
  • 2
  • 12
-7

A friend of mine suggested this as well, and it worked!

<h2>Success!</h2>
{{#each data}}
 <div>
    Name: {{ LocalizedName }}<br>
    Rank: {{ Rank }}<br>
 </div> 
 {{/each}}
Jay Aigner
  • 15
  • 2