Question

I was trying to create a helper that would let me chain helpers together like:

{{ chain "striptags" "<p>asdf</p>" "truncate" 2 }}

But it seems like instead of returning the value after calling a helper in Ember, the last arg has a rendering buffer which gets manipulated by the ember helper. Is there a way to take a normal ember handlebars helper and return the value? My reference code:

/**
 * Allows some basic chaining of helpers.
 * {{ chain "helper1" arg1 arg2 "helper2" arg2 }}
 */
Ember.Handlebars.helper('chain', function() {
  var helperArgs = [];
  var helper;
  var that = this;
  var options = arguments[arguments.length - 1];
  $.each(arguments, function(i, arg) {
    if(Ember.Handlebars.helpers[arg]){
      if(helper){
        helperArgs.push(options);
        helperArgs = [helper.apply(that, helperArgs)];
      }
      helper = Ember.Handlebars.helpers[arg];
    }else{
      helperArgs.push(arg);
    }
  });
  return helper.apply(that, helperArgs);
});
Was it helpful?

Solution

This will sort of work:

Ember.Handlebars.helper('chain', function() {
    var that = this,
    helpers = [],
    current = null,
    options = arguments[arguments.length - 1];
    for (var i = 0; i < arguments.length - 1; i++) {
        var arg = arguments[i],
        helperFn = Ember.Handlebars.helpers[arg];
        if (helperFn) {
            current = {
                fn: helperFn,
                args: []
            };
            helpers.push(current);
        }
        else if (current) {
            current.args.push(arg);
        }
        else {
            throw new Error("Unknown helper: " + arg);
        }
    }
    var prevResult = null;
    $.each(helpers, function (index, helper) {
        var args = helper.args.concat(options),
            before = options.data.buffer.buffer;
        if (prevResult) {
            args.unshift(prevResult);
        }
        helper.fn.apply(that, args);
        var after = options.data.buffer.buffer;
        prevResult = after.slice(before.length).replace(/<\/?script[^>]*>/g, "");
        if (index < helpers.length - 1) {
            options.data.buffer.buffer = before;
        }
    });
});

JSBin.

The problem is, handlebars helpers don't really return a value. Instead, they write directly into the buffer provided through options argument. In the example above, I directly manipulate this buffer to extract product of one helper and insert it as the first argument of the next helper (stripping out ember metatags is just a bonus of WTF-ery).

As you can see, it works in this simple use case, but will probably break for anything more involved. Handlebars helpers just weren't designed to be used as functions.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top