Search code examples
javascripthandlebars.jshandlebarshelper

Handlebars subexpression throws "options.fn is not a function" error


I'm trying to use subexpression in Handlebars but getting "options.fn is not a function" error even on simplest expression. While using additional helpers from https://github.com/assemble/handlebars-helpers, this expression works fine:

{{#and true true}}OK{{/and}}

But if I make a subexpression like this

{{#and (gt 4 3) (gt 5 4)}}OK{{/and}}

Or this

{{#and (gt 4 3) true}}OK{{/and}}

The library throws an error

TypeError: [feed.hbs] options.fn is not a function
   at Object.helpers.gt (/Users/me/Projects/jackal/node_modules/handlebars-helpers/lib/comparison.js:152:20)
   at Object.eval (eval at createFunctionContext ...

I need to have a check for two conditions. At this time it achieved with nested expressions:

{{#gt 4 3}}
    {{#gt 5 4}}
        ok
    {{/gt}}
{{/gt}}

So whats wrong with my subexpressions?


Solution

  • To me it looks like that subexpressions are not supported by handlebars-helpers that way.

    I had a short look at at the code with the debugger. For the {{#and (gt 4 3) (gt 5 4)}}OK{{/and}} and the (gt 4 3) itself is called correctly, but the code of the gt helper is:

    helpers.gt = function(a, b, options) {
      if (arguments.length === 2) {
        options = b;
        b = options.hash.compare;
      }
      if (a > b) {
        return options.fn(this);
      }
      return options.inverse(this);
    };
    

    But because subexpressions do neither have a fn (if block), nor a inverse (else block), the handlebars-helpers fails at this point.

    To support your expression the handlebars-helpers need - IMHO - rewrite their code to something like that:

    helpers.gt = function(a, b, options) {
      if (arguments.length === 2) {
        options = b;
        b = options.hash.compare;
      }
    
      //fn block exists to it is not a subexpression
    
      if( options.fn ) {
         if (a > b) {
           return options.fn(this);
         }
         return options.inverse(this);
      } else {
         return a > b;
      }
    };
    

    So for now you can't use subexpressions with handlebars-helpers.

    I added an Issue on their github page: Supporting Handlebars subexpressions