ericf / express-handlebars

A Handlebars view engine for Express which doesn't suck.
BSD 3-Clause "New" or "Revised" License
2.31k stars 384 forks source link

Rendering inner template of custom block helpers #163

Closed benoitdevrieze closed 8 years ago

benoitdevrieze commented 8 years ago

I want to write a block helper for express-handlebars which joins elements of an array:

For example:

title = ['Page', 'Site']
<title>{{join title delimiter = " - "}}</title>

Should result in:

<title>Page - Title</title>

Which works great with the following helper code:

function(context, options) {
  var delimiter = options.hash.delimiter || ",";
  return [].concat(context).join(delimiter);
}

But also the following:

breadcrumbs = [ { name: 'level 1', url: '/' }, { name: 'level 2', url: '/path' } ]
{{#join breadcrumbs delimiter = " / "}}
<a href="{{url}}">{{name}}</a>
{{/join}}

Should result in:

<a href="/">level 1</a> / <a href="/path">level 2</a>

Now, for this scenario to be possible, there must be a way to render the inner template of the block helper in the helper code. This must be possible because the built-in helpers provide the same functionality.

See the following example from the handlebarsjs documentation:

Handlebars.registerHelper('each', function(context, options) {
  var ret = "";
  for(var i=0, j=context.length; i<j; i++) {
    ret = ret + options.fn(context[i]);
  }
  return ret;
});

The element which makes the scenario work is the options.fn fucntion, rendering the inner template based on the context. This function is missing when creating a helper for handlebars-express.

The code below results in an error because options.fn is undefined.

function(context, options) {
  var delimiter = options.hash.delimiter || ",";
  return [].concat(context).map(options.fn).join(delimiter);
}
benoitdevrieze commented 8 years ago

I have made a mistake. It does work perfectly. The helper code should be:

module.exports.join = function(context, options) {
  var delimiter = options.hash.delimiter || ",";
  if (options.fn) {
    return [].concat(context).slice(start, end).map(options.fn).join(delimiter);
  } else {
    return [].concat(context).slice(start, end).join(delimiter);
  }
}