Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Conditional rendering of template in Handlebars

In Handlebars, default renders nothing when no context data is provided:

e.g. title: {{ title }} will render title: if no title variable is provided in context

I would like to build a helper that correctly evaluates a template when context is provided, but displays the actual mustache template when no context variable is provided.

Here is a Plunk that illustrates this idea

I could manage to conditionally display either rendering or the template using the following code:

{{#unless title}}
  {{{{raw-helper}}}}
  <h2>title: {{title}}</h2>
  {{{{/raw-helper}}}}
{{else}}
  <h2>title: {{title}}</h2>
{{/unless}}

But I thought a more elegant, and reusable solution, would be to create a specific helper. I would use it like so:

{{#raw-unless body}}
    body: {{body}}
{{/raw-unless}}

If body string is not empty / null / undefined, it would render:

body: 'this is the body provided in context'

And if body is not provided, it would render:

body: {{body}}

So far, I tried to register the helper like so:

Handlebars.registerHelper('raw-unless', function(data, options) {
if(data) {
return options.fn(this);
}
else {
  var out = '{{#raw-helper}}';// 
  out += options.fn();
  out += '{{/raw-helper}}';// 
return out;
}
});

But it renders: {{#raw-helper}} body: {{/raw-helper}}


I am not to familiar with custom helper creations, any help appreciated

like image 494
Manube Avatar asked Oct 24 '25 16:10

Manube


2 Answers

I don't think you are going to be able to get the pre-compiled template source from within your block helper. Therefore, I see two options for you: passing the default value directly to your helper or passing a string key to your helper so that the helper can format the default value.

The first option is more versatile because it allows the template to define the default output:

Handlebars.registerHelper('render1', function (value, defaultValue) {
    return value || defaultValue;
});

You would use it in your template in the following way:

body: {{render1 body '{{body}}'}}

If you don't need the convenience of defining your default text in your template, then the second option is attractive because it is concise:

Handlebars.registerHelper('render2', function (key) {
    return this[key] || '{{' + key + '}}';
});

And it would be used in your template as:

body: {{render2 'body'}}

For your reference, I have forked and updated your plunk.


EDIT by OP

To handle incorrect use of the helper, I ended up tweaking it like so:

Handlebars.registerHelper('render1', function (value, defaultValue) {
  var v = (typeof value ==='string')?value:null;
  var d = (typeof defaultValue === 'string')?defaultValue:'ERROR: undefined model / no default value provided';
  return v || d;
});

It will handle misuses of the helper, like:

body: {{render1 body}}

when body is not provided in context and default value is not provided, or:

body: {{render1}}

when the model is undefined

like image 172
76484 Avatar answered Oct 26 '25 06:10

76484


Since you're not sending body in context, it is rejecting

{{#raw-unless body}}
    body: {{body}}
{{/raw-unless}}

So in the else condition return the text what you want to display. In this case

Handlebars.registerHelper('raw-unless', function(data, options) {
  if (data) {
    return options.fn(this);
  } else {
    return '{{body}}'
  }
});
like image 24
pmaddi Avatar answered Oct 26 '25 04:10

pmaddi



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!