Search code examples
javascriptnode.jsexpresshelperhandlebars.js

Node Express Handlebars helper not returning result of function


I'm baffled on this one. If I use a function within a handlebars helper and return the result of that function, nothing is returned.

Here is the template:

<ul>
    <li>{{formatid this.id}}</li>
</ul>

And here is the helper:

formatid : function(id){
    mOrders.formatOrderID(id, function(err, formatted_id){
        // err is always null, no need to handle
        console.log(formatted_id);
        return formatted_id;
    });
}

Yet despite the correct text being logged to the console, the resultant html is:

<ul>
    <li></li>
</ul>

If, however, I put a return after the end of the formatOrderID() function, it gets returned, so this:

formatid : function(id){
    mOrders.formatOrderID(id, function(err, formatted_id){
        // err is always null, no need to handle
        console.log(formatted_id);
        return formatted_id;
    });
    return 'some_text';
}

gives me the following html:

<ul>
    <li>some_text</li>
</ul>

What am I missing here? It's not the returned formatted string, as even when I return a string within the callback it's ignored.


Solution

  • The problem is that you are trying to return a value from an asynchronous function, but handlebars helpers are synchronous. By the time the callback passed in mOrders.formatOrderID() gets executed your helper function already exited (with value undefined, since you didn't return anything outside the callback in your first example, and with 'some_text' in your second example).

    One solution is to make mOrders.formatOrderID be synchronous (if possible or feasible) or use a library like express-hbs and define asynchronous helpers like this:

    var hbs = require('express-hbs');
    
    hbs.registerAsyncHelper('formatid', function(id, cb) {
      mOrders.formatOrderID(id, function(err, formatted_id){
        // err is always null, no need to handle
        console.log(formatted_id);
        cb(formatted_id);
      });
    });