简体   繁体   中英

Conditional rendering of template in Handlebars

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

eg 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

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

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}}'
  }
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM