Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to set default arguments for Handlebars templates?

I've written a template helper that inserts a link, fairly straightforward.

Handlebars.registerHelper('link_to', function(href, title) {
    return new Handlebars.SafeString('<a href="/' + href + '">' + title + '</a>');
});

And its usage is like so:

{{ link_to 'articles' 'Articles' }}

However, it seems a bit redundant for me to specify a capitalised version in the second parameter if the href is self-describing. So I'd like to set this behaviour automatically if the title parameter is omitted. Something like the following:

Handlebars.registerHelper('link_to', function(href, title) {
    if (!title) {
        title = href.charAt(0).toUpperCase() + href.slice(1);
    }
    return new Handlebars.SafeString('<a href="/' + href + '">' + title + '</a>');
});

However, when rendered with {{ link_to 'articles' }} I just get [object Object]. It's not a big deal to keep the second parameter, but I was just wondering if there was a way around this.

like image 396
Ben Avatar asked Nov 03 '14 00:11

Ben


3 Answers

Helpers accept an optional Hash as its final argument.If the template provides no hash arguments, Handlebars will automatically pass an empty object ({}).

[From https://handlebars-lang.github.io/docs/guide/block-helpers.html#hash-arguments ]

So, when you are having title in the helpers parameter list it is treated as the Hash object. You can check that by logging title in console. So for your code to work you can just check that if the type of title is String or not using the typeof operator.

if(!title || typeof title != 'String') {
    title = href.toString().charAt(0).toUpperCase() + href.slice(1);
}

and it should work. Working example : http://jsfiddle.net/prabhat_rai/ve4h39vm/

like image 76
Prabhat Rai Avatar answered Oct 28 '22 18:10

Prabhat Rai


The correct way to use the hash arguments in handlebars seems to be to check for the expected optional parameters in the hash attribute of the options argument (passed to any helper as last argument).

In the OP example this would look like this:

Handlebars.registerHelper('link_to', function(href) {
    var options = arguments[arguments.length - 1];
    var title = options.hash.title || href.toString().charAt(0).toUpperCase() + href.slice(1);
    return new Handlebars.SafeString('<a href="/' + href + '">' + title + '</a>');
});

This way the helper can be used like this

{{ link_to 'articles' title='Articles' }}

or this

{{ link_to 'articles' }}

This has the advantage that you can add any number of optional template arguments and not just one. That is the above example could easily extended to provide an optional tooltip as well:

Handlebars.registerHelper('link_to', function(href) {
    var options = arguments[arguments.length - 1];
    var title = options.hash.title || href.toString().charAt(0).toUpperCase() + href.slice(1);
    var tooltip = options.hash.tooltip || title;
    return new Handlebars.SafeString('<a href="/' + href + '" title="' + tooltip + '">' + title + '</a>');
});

Now both title and tooltip can be specified independent of each other. I.e. you can specify a tooltip but no custom title:

{{ link_to 'articles' tooltip='Go to Articles' }}
like image 37
dpr Avatar answered Oct 28 '22 18:10

dpr


fix your helpers. The options object makes this difficult. So by wrapping the functions with something that moves around the arguments you have more reasonable code assuming you will have multiple helpers with optional arguments

function fixHelper(func) {
  return function(){
    var aArgs=Array.prototype.slice.call(arguments, 0)
      ,opts=aArgs.pop();
    aArgs.unshift(opts);
    return func.apply(this, aArgs);
  }

 function link_to(options, href, title) {
    title = title || href.ucfirst()
    return new Handlebars.SafeString('<a href="/' + href + '">' + title + '</a>')
 }
 Handlebars.registerHelper('link_to', fixHelper(link_to))
like image 44
user11199464 Avatar answered Oct 28 '22 18:10

user11199464