Handlebars.js: 1つのタグで複数のヘルパーを使用できますか?

作成日 2012年09月07日  ·  17コメント  ·  ソース: handlebars-lang/handlebars.js

{{ helper1 helper2 text }}ように、作業を行うのに1人のヘルパーだけでは不十分な場合があります。

最も参考になるコメント

これは、次のようなものを使用してネイティブサポートを持っているようです。

{{ 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}}

jQueryへの依存関係を導入する@Znarkus

@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();
});

両方の実装に関する1つの問題は、注目に値します。引数のいずれかがヘルパーに渡される値として意図されているが、既存のヘルパーの名前と一致する(強制可能な)文字列である場合、予期しない結果が発生します。

これが2つの実装です。 前の例とは異なり、どちらも複数の引数を各ヘルパーに送信できます。
それらはまた、コーヒースクリプトで書かれており、アンダースコアまたは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

この2番目の例には、 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あなたのメソッドを使用して、安全な文字列が適用されている2つのヘルパーを渡すと、コードブレークが発生します。 初めてデータを渡すと文字列として入力されますが、2番目のフィルターで渡される値はオブジェクトのように見えますか? 私のデバッガーでは、「na改行」、次に「文字列」と表示されます。 SafeStringが値に対して何をするかはわかりませんが、SafeStringを2回渡すと、うまく機能しないようです。

    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アプローチは@cssagogoのようにHandlebars.SafeString()がないだけです。

だからあなたはsmthを行うことができます。 お気に入り:

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

ありがとう

私は自分でこの問題に遭遇しました。 私はこれに本当に遅れていることを知っていますが、私は私のために働いた解決策を持っています。 これがすでに言及されている場合はご容赦ください(私は時間をかけて確認しませんでした)。 これは最もクールな解決策ではなく、技術的には質問に対する直接の答えではありませんが、問題の解決策です(1つの値で複数の関数を実行する)。

すべてのヘルパー関数を別のファイルに保存しています。 それらはすべて同じ場所にあるため、1つのヘルパーに値を渡してから、ヘルパー関数のファイルにある他の関数を呼び出すことができます。 そう:

{{ 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 評価