I really like the handlebars template system, it’s straight to the point, efficient, and the added logic layer to mustache makes it practical for most scenarios.
One limitation i’ve found was that if
block helpers can’t actually evaluate an expression, it only tests if the passed value is already true or false, there’s no evaluation of it.
so this:
{{#if unicorns == ponies }}
That's amazing, unicorns are actually undercover ponies
{{/if}}
doesn’t work, bummer.
I initially needed to do just that (the == bit, not the unicorns & ponies assertion) so I wrote a basic block helper that checks if two values are equal.
This is done quite simply like this:
Handlebars.registerHelper('equal', function(lvalue, rvalue, options) {
if (arguments.length < 3)
throw new Error("Handlebars Helper equal needs 2 parameters");
if( lvalue!=rvalue ) {
return options.inverse(this);
} else {
return options.fn(this);
}
});
You can then rewrite the handlebar template code above as:
{{#equal unicorns ponies }}
That's amazing, unicorns are actually undercover ponies
{{/equal}}
Then I thought, what if I want to check if the unicorns are bigger than the ponies, or if the ponies and unicorns are the same type.. ?
You could easily write a helper for each comparison operator but that would be a bit long.
Handlebars allows you to pass extra named attributes called hashed arguments to the block helper.
These can then be retrieved inside the helper through the options.hash
attributes.
So I made the equal
helper a more generic compare
helper. It still takes 2 parameters, but you can also pass an optional operator
hashed argument. If you omit the operator argument it default to ==
.
Here’s the full code:
Handlebars.registerHelper('compare', function(lvalue, rvalue, options) {
if (arguments.length < 3)
throw new Error("Handlerbars Helper 'compare' needs 2 parameters");
var operator = options.hash.operator || "==";
var operators = {
'==': function(l,r) { return l == r; },
'===': function(l,r) { return l === r; },
'!=': function(l,r) { return l != r; },
'<': function(l,r) { return l < r; },
'>': function(l,r) { return l > r; },
'<=': function(l,r) { return l <= r; },
'>=': function(l,r) { return l >= r; },
'typeof': function(l,r) { return typeof l == r; }
}
if (!operators[operator])
throw new Error("Handlerbars Helper 'compare' doesn't know the operator "+operator);
var result = operators[operator](lvalue,rvalue);
if( result ) {
return options.fn(this);
} else {
return options.inverse(this);
}
});
And now you can do this:
{{#compare unicorns ponies operator="<"}}
I knew it, unicorns are just low-quality ponies!
{{/compare}}
Have fun!
Edit: Thanks to paul for pointing out in the comments section the misuse of the helper syntax, it should have been a block helper starting with a #.
Edit 2: Mike Griffin has a nice alternative version of this in the comments
License: Licensed under MIT License