Handlebars.js: 我可以在一个标签中使用多个助手吗?

创建于 2012-09-07  ·  17评论  ·  资料来源: handlebars-lang/handlebars.js

就像{{ helper1 helper2 text }} ,您知道有时只有一个助手是不够的。

最有用的评论

这似乎具有使用以下内容的本机支持:

{{ helper1 (helper2 text) }}

所有17条评论

我认为需要一种嵌套表达式的方法,例如: {{headerText {{getTitle "my_page"}}}}

目前不支持,我也没有计划支持它。

但是,理论上您可以创建一个故意消耗和链接其他助手的助手:

{{chain "helper1" "helper2" text}}

如果有人感兴趣,我已经创建了这样一个帮手:

Handlebars.registerHelper('chain', function () {
    var helpers = [], value;
    $.each(arguments, function (i, arg) {
        if (Handlebars.helpers[arg]) {
            helpers.push(Handlebars.helpers[arg]);
        } else {
            value = arg;
            $.each(helpers, function (j, helper) {
                value = helper(value, arguments[i + 1]);
            });
            return false;
        }
    });
    return value;
});

像这样工作:

{{chain "taxAdd" "formatPrice" this.product.price}}

@Znarkus引入了对 jQuery 的依赖

@jrajan我只使用了jQuery.each ,您可以根据自己的喜好随意重写它。

如果有人对 jQuery 不可知版本感兴趣:

Handlebars.registerHelper('chain', function() {
  var helpers = [];
  var args = Array.prototype.slice.call(arguments);
  var argsLength = args.length;
  var index;
  var arg;

  for (index = 0, arg = args[index];
       index < argsLength;
       arg = args[++index]) {
    if (Handlebars.helpers[arg]) {
      helpers.push(Handlebars.helpers[arg]);
    } else {
      args = args.slice(index);
      break;
    }
  }

  while (helpers.length) {
    args = [helpers.pop().apply(Handlebars.helpers, args)];
  }

  return args.shift();
});

两种实现的一个问题值得注意:如果任何参数旨在作为传递给帮助程序的值,但碰巧是(强制)匹配现有帮助程序名称的字符串,则会出现意外结果。

这里有两个实现。 与前面的示例不同,它们都允许您将多个参数发送给每个助手。
它们也是用咖啡脚本编写的,依赖于下划线或 lodash。

第一个允许你做这样的事情:
{{{chain 'join-strings' 'link-twitter-handles' '@' twitterUsername}}}
但是这样的事情会产生意想不到的结果:
{{{chain 'join-strings' 'link-twitter-handles' '@' 'join-strings' twitterUsername}}}

Handlebars.registerHelper 'chain', ->
    # Get rid of the options hash
    args = Array.prototype.slice.call arguments, 0, -1
    helpers = []
    argsForHelpers = null
    value = undefined

    _.each args, (arg, i) ->
        if Handlebars.helpers[arg]
            helpers.push Handlebars.helpers[arg]
        else if not value # Only call the helpers once
            value = arg
            unless argsForHelpers
                argsForHelpers = args[i+1..-1]
                argsForHelpers.unshift value
            _.each helpers, (helper) ->
                argsForHelpers[0] = value
                value = helper.apply null, argsForHelpers

    value

第二个例子有一个分隔符,它让chain从参数中分离助手。
助手将假定分隔符之前的每个参数都是助手,所有其他参数都应作为参数传递给助手。

Handlebars.registerHelper 'chain', ->
    # Get rid of the options hash
    args = Array.prototype.slice.call arguments, 0, -1
    helpers = []

    for arg,i in args
        if arg is '--'
            argsForHelpers = args.slice i + 1
            value = argsForHelpers[0]
            break
        else
            helpers.push Handlebars.helpers[arg]

    _.each helpers, (helper) ->
        argsForHelpers[0] = value
        value = helper.apply null, argsForHelpers

    value

鉴于此模板:
{{{chain 'join-strings' 'link-twitter-handles' '@' 'join-strings' twitterUsername}}}
和这个对象:
{twitterUsername: 'abc'}
我们可以期待这样的编译模板:
<a href="https://twitter.com/join-stringsabc">@join-stringsabc</a>

我已经采用了@cdata的实现并将其变成了块助手的版本。 我还要求助手名称以 '!!' 为前缀避免参数匹配助手名称的问题。

/**
 * Takes an arbitrary number of arguments, the first of which is the operation type 'AND' or 'OR'.
 * Following that will be a list of block helper names prefixed by '!!'.
 * Calls each block helper with the remaining arguments.
 *
 * <strong i="7">@returns</strong> {string}  returns options.fn(this) or options.inverse(this) depending on result of each helper and operation type
 */
Handlebars.registerHelper('chainBlockHelpers', function() {
    var index, arg, helperResult, pass,
        helpers = [],
        args = Array.prototype.slice.call(arguments),
        argsLength = args.length,
        options = args[argsLength-1],
        operation = args.shift(),
        passVal = options.fn(this),
        failVal = options.inverse(this);

    if (operation !== 'AND' && operation !== 'OR')
        throw new Error ('chainBlockHelpers only supports "AND" or "OR" operations.')

    for (index = 0, arg = args[index]; index < argsLength; arg = args[++index]) {
        if (typeof arg == 'string' && arg.startsWith('!!') && Handlebars.helpers[arg.substr(2)]) {
            helpers.push(Handlebars.helpers[arg.substr(2)]);
        } else {
            args = args.slice(index);
            break;
        }
    }

    if (operation === 'AND') {
        pass = true;
        while (helpers.length) {
            helperResult = helpers.pop().apply(Handlebars.helpers, args);
            if (helperResult == failVal) {
                pass = false;
                break;
            }
        }
    } else {
        pass = false;
        while (helpers.length) {
            helperResult = helpers.pop().apply(Handlebars.helpers, args);
            if (helperResult == passVal) {
                pass = true;
                break;
            }
        }
    }

    return pass ? passVal : failVal;
});

这似乎具有使用以下内容的本机支持:

{{ helper1 (helper2 text) }}

在某些情况下,你可以让你的助手像这样工作:

{{#helper1}}{{helper2}}content{{/helper2}}{{/helper1}}

@Znarkus使用你的方法,当我传入两个具有安全字符串的助手时,我的代码中断了。 我第一次通过它传递数据时以字符串形式传入,但第二个过滤器传递的值似乎是一个对象? 在我的调试器中,它显示为 'na line break and then string:'my value'; 不确定 SafeString 对值有什么作用,但将它传递两次似乎效果不佳。

    Handlebars.registerHelper('shortNumber', function (value) {
        //return new Handlebars.SafeString(iSpot.number.shortNumber(value)); // Breaks
        return iSpot.number.shortNumber(value);  // Works
    });
    Handlebars.registerHelper('asDollars', function (value) {
        //return new Handlebars.SafeString(iSpot.number.asDollars(value)); // Breaks
        return iSpot.number.asDollars(value); // Works
    });

+1 @amwmedia方法 - {{pluralize (titleize (humanize schema.name))}}

+1 看起来像一个漂亮干净的语法。

+1 @amwmedia非常感谢

@breandr / @amwmedia方法就像一个Handlebars.SafeString()就像上面提到的

所以你可以做某事。 喜欢:

{{> partial text=(concat value (default extension 'PDF')) }}

谢谢

我自己遇到了这个问题。 我知道我真的迟到了,但我有一个对我有用的解决方案。 如果已经提到过,请原谅我(我没有花时间检查)。 这不是最酷的解决方案,从技术上讲,它不是您问题的直接答案,但它是问题的解决方案(在一个值上运行多个函数)。

我将所有辅助函数保存在一个单独的文件中。 因为它们都在同一个地方,所以我可以将值传递给一个助手,然后调用助手函数文件中的任何其他函数。 所以:

{{ function1 value }}

帮助文件

function2 (value) {
   // code
}

function1 (value) {
   // code
   function2(value)
   // code
   return value;
}

当然,这是一种能够根据需要使用尽可能多的功能的简单方法。 您甚至可以指定一个基本函数作为您的“链接器”。

{{ chainer value }}

帮助文件

function1 (value) {
   // code
}
function2 (value) {
   // code
}
function3 (value) {
   // code
}
function4 (value) {
   // code
}

function chainer(value) {
   function1(value)
   function2(value)
   function3(value)
   function4(value)
   return value;
}

我自己没有这样做,但我不明白为什么它不起作用。

注意您只需将要在 html 中使用的函数注册为把手助手。 我个人已经注册了我的所有内容,因为我彼此独立使用它们,但是如果您不预见自己需要直接使用它,则不必这样做。

回归过程式编程:)

此页面是否有帮助?
0 / 5 - 0 等级

相关问题

stevenvachon picture stevenvachon  ·  15评论

robincsamuel picture robincsamuel  ·  24评论

eotope picture eotope  ·  20评论

jstewmon picture jstewmon  ·  11评论

nknapp picture nknapp  ·  13评论