handlebars.js {{#if}}条件付きの論理演算子


479

ハンドルバーJSで論理演算子を標準のhandlebars.js条件演算子に組み込む方法はありますか?このようなもの:

{{#if section1 || section2}}
.. content
{{/if}}

自分のヘルパーを作成できることはわかっていますが、最初に、ホイールを再発明しないようにしたいと思います。

回答:


519

これは、ブロックヘルパーで「不正行為」を行うことで可能になります。これはおそらく、ハンドルバーを開発した人々のイデオロギーに反します。

Handlebars.registerHelper('ifCond', function(v1, v2, options) {
  if(v1 === v2) {
    return options.fn(this);
  }
  return options.inverse(this);
});

次に、このようにテンプレートでヘルパーを呼び出すことができます

{{#ifCond v1 v2}}
    {{v1}} is equal to {{v2}}
{{else}}
    {{v1}} is not equal to {{v2}}
{{/ifCond}}

54
これは、ハンドルバー/ Moustacheの論理のない性質に反しますが、それでも確かに便利です、ありがとう!
Bala Clark

6
これは単にバインドされたプロパティ(読み取り、Emberバインディング)では機能しないことに注意してください。リテラル値で問題ありませんが、モデルのプロパティ(Ember 1.0.0-rc.8およびHandlebars 1.0.0でテスト済み)を解決せずregisterBoundHelper、Handlebars構文を処理できません。この問題を回避するには、カスタムビューを作成することです:stackoverflow.com/questions/18005111/...
ウォーレン・セーヌ

28
@BalaClarkは本当に無論理ですか?つまり、「if」ステートメントがまだ残っているということです。意図的に不自由にされているからといって、哲学は変わりません。
phreakhead 2014

111
開発者がハンディキャップを好む理由を理解できませんでした。
StackOverflowed 2014年

36
AND / ORをハンドルバーの一部にできない理由がわかりません。IF、UNLESS、EACHがすでに存在するため、ロジックレスの性質に逆らうことはできません...ロジックレスにはそれだけ
Asaf

445

ソリューションをさらに一歩進めます。これにより、比較演算子が追加されます。

Handlebars.registerHelper('ifCond', function (v1, operator, v2, options) {

    switch (operator) {
        case '==':
            return (v1 == v2) ? options.fn(this) : options.inverse(this);
        case '===':
            return (v1 === v2) ? options.fn(this) : options.inverse(this);
        case '!=':
            return (v1 != v2) ? options.fn(this) : options.inverse(this);
        case '!==':
            return (v1 !== v2) ? options.fn(this) : options.inverse(this);
        case '<':
            return (v1 < v2) ? options.fn(this) : options.inverse(this);
        case '<=':
            return (v1 <= v2) ? options.fn(this) : options.inverse(this);
        case '>':
            return (v1 > v2) ? options.fn(this) : options.inverse(this);
        case '>=':
            return (v1 >= v2) ? options.fn(this) : options.inverse(this);
        case '&&':
            return (v1 && v2) ? options.fn(this) : options.inverse(this);
        case '||':
            return (v1 || v2) ? options.fn(this) : options.inverse(this);
        default:
            return options.inverse(this);
    }
});

次のようなテンプレートで使用します。

{{#ifCond var1 '==' var2}}

Coffee Scriptバージョン

Handlebars.registerHelper 'ifCond', (v1, operator, v2, options) ->
    switch operator
        when '==', '===', 'is'
            return if v1 is v2 then options.fn this else options.inverse this
        when '!=', '!=='
            return if v1 != v2 then options.fn this else options.inverse this
        when '<'
            return if v1 < v2 then options.fn this else options.inverse this
        when '<='
            return if v1 <= v2 then options.fn this else options.inverse this
        when '>'
            return if v1 > v2 then options.fn this else options.inverse this
        when '>='
            return if v1 >= v2 then options.fn this else options.inverse this
        when '&&', 'and'
            return if v1 and v2 then options.fn this else options.inverse this
        when '||', 'or'
            return if v1 or v2 then options.fn this else options.inverse this
        else
            return options.inverse this

20
忘れてはいけない'||''&&'。これらのケースを追加しましたが、非常に便利です。
Jason

20
ハンドルバーのnoobであることの1つが明確ではなかったことは、演算子を文字列として渡す必要があることです。そうしないと、テンプレートのトークン化中にコンパイラーがエラーになります。{{#ifCond true '==' false}}
ジョーホロウェイ

2
オブジェクトの属性に対して値が評価されないことがわかりました。次のv1 = Ember.Handlebars.get(this, v1, options) v2 = Ember.Handlebars.get(this, v2, options)
ヘルプを

4
しかし、v1とv2も1つの条件の場合、どのように使用できますか?例:if(value == "a" || value == "b")
クリシュナ

3
これで他のことができますか?
jbyrd 16

160

ハンドルバーはネストされた操作をサポートしています。これにより、ロジックを少し異なる方法で記述した場合に、多くの柔軟性(およびよりクリーンなコード)が提供されます。

{{#if (or section1 section2)}}
.. content
{{/if}}

実際、あらゆる種類のロジックを追加できます。

{{#if (or 
        (eq section1 "foo")
        (ne section2 "bar"))}}
.. content
{{/if}}

これらのヘルパーを登録するだけです:

Handlebars.registerHelper({
    eq: (v1, v2) => v1 === v2,
    ne: (v1, v2) => v1 !== v2,
    lt: (v1, v2) => v1 < v2,
    gt: (v1, v2) => v1 > v2,
    lte: (v1, v2) => v1 <= v2,
    gte: (v1, v2) => v1 >= v2,
    and() {
        return Array.prototype.every.call(arguments, Boolean);
    },
    or() {
        return Array.prototype.slice.call(arguments, 0, -1).some(Boolean);
    }
});

5
これは、Ember 1.10のHTMLBarsまで不可能であったことに注意してください。また、これらのヘルパーは、必要に応じてEmber CLIアドオンとして提供されます:github.com/jmurphyau/ember-truth-helpers
stephen.hanson 2015

1
このように、options実行しないことは、ifメソッドを保持する方が良く、テストが容易です。ありがとう!
ワシントンBotelho

25
Lispをハンドルバーに組み込んだようです。
jdunning

8
あなたandorヘルパーあなたが望むものではない2つのパラメータを持つ唯一の作品。2つ以上のパラメーターをサポートするために、andorヘルパーの両方を再構築することができました。このワンライナーをandreturn Array.prototype.slice.call(arguments, 0, arguments.length - 1).every(Boolean);に使用し、このワンライナーを:に使用しorますreturn Array.prototype.slice.call(arguments, 0, arguments.length - 1).some(Boolean);
ルーク、

3
もう少し高度なバージョン、各オペレータに複数のパラメータを取ることができます。
2018

87

端に住んでいるあなたのために、これを一段上に上げてください。

gisthttps : //gist.github.com/akhoury/9118682 Demo:以下のコードスニペット

ハンドルバーヘルパー: {{#xif EXPRESSION}} {{else}} {{/xif}}

任意の式でIFステートメントを実行するヘルパー

  1. EXPRESSIONは適切にエスケープされた文字列です
  2. はい、あなたはNEED適切に文字列リテラルまたはちょうど別の単一引用符と二重引用符をエスケープします
  3. つまり、グローバル関数やプロパティにアクセスできます。 encodeURIComponent(property)
  4. この例では、あなたのハンドルバーにこのコンテキストを通過したと仮定しtemplate( {name: 'Sam', age: '20' } )、通知がageあるstringだけで、私はデモことができるようにするために、parseInt()後でこの投稿で

使用法:

<p>
 {{#xif " name == 'Sam' && age === '12' " }}
   BOOM
 {{else}}
   BAMM
 {{/xif}}
</p>

出力

<p>
  BOOM
</p>

JavaScript:(それは別のヘルパーに依存します- 読み続けてください)

 Handlebars.registerHelper("xif", function (expression, options) {
    return Handlebars.helpers["x"].apply(this, [expression, options]) ? options.fn(this) : options.inverse(this);
  });

ハンドルバーヘルパー: {{x EXPRESSION}}

JavaScript式を実行するヘルパー

  1. EXPRESSIONは適切にエスケープされた文字列です
  2. はい、あなたはNEED適切に文字列リテラルまたはちょうど別の単一引用符と二重引用符をエスケープします
  3. つまり、グローバル関数やプロパティにアクセスできます。 parseInt(property)
  4. この例では、あなたのハンドルバーにこのコンテキストを通過したと仮定しtemplate( {name: 'Sam', age: '20' } )ageあるstringデモの目的のために、それは何もすることができます。..

使用法:

<p>Url: {{x "'hi' + name + ', ' + window.location.href + ' <---- this is your href,' + ' your Age is:' + parseInt(this.age, 10)"}}</p>

出力:

<p>Url: hi Sam, http://example.com <---- this is your href, your Age is: 20</p>

JavaScript:

構文を拡張し、明確にするためにほとんどすべての行にコメントを付けたため、これは少し大きく見えます

Handlebars.registerHelper("x", function(expression, options) {
  var result;

  // you can change the context, or merge it with options.data, options.hash
  var context = this;

  // yup, i use 'with' here to expose the context's properties as block variables
  // you don't need to do {{x 'this.age + 2'}}
  // but you can also do {{x 'age + 2'}}
  // HOWEVER including an UNINITIALIZED var in a expression will return undefined as the result.
  with(context) {
    result = (function() {
      try {
        return eval(expression);
      } catch (e) {
        console.warn('•Expression: {{x \'' + expression + '\'}}\n•JS-Error: ', e, '\n•Context: ', context);
      }
    }).call(context); // to make eval's lexical this=context
  }
  return result;
});

Handlebars.registerHelper("xif", function(expression, options) {
  return Handlebars.helpers["x"].apply(this, [expression, options]) ? options.fn(this) : options.inverse(this);
});

var data = [{
  firstName: 'Joan',
  age: '21',
  email: 'joan@aaa.bbb'
}, {
  firstName: 'Sam',
  age: '18',
  email: 'sam@aaa.bbb'
}, {
  firstName: 'Perter',
  lastName: 'Smith',
  age: '25',
  email: 'joseph@aaa.bbb'
}];

var source = $("#template").html();
var template = Handlebars.compile(source);
$("#main").html(template(data));
h1 {
  font-size: large;
}
.content {
  padding: 10px;
}
.person {
  padding: 5px;
  margin: 5px;
  border: 1px solid grey;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/handlebars.js/1.0.0/handlebars.min.js"></script>

<script id="template" type="text/x-handlebars-template">
  <div class="content">
    {{#each this}}
    <div class="person">
      <h1>{{x  "'Hi ' + firstName"}}, {{x 'lastName'}}</h1>
      <div>{{x '"you were born in " + ((new Date()).getFullYear() - parseInt(this.age, 10)) '}}</div>
      {{#xif 'parseInt(age) >= 21'}} login here:
      <a href="http://foo.bar?email={{x 'encodeURIComponent(email)'}}">
        	http://foo.bar?email={{x 'encodeURIComponent(email)'}}
        </a>
      {{else}} Please go back when you grow up. {{/xif}}
    </div>
    {{/each}}
  </div>
</script>

<div id="main"></div>

モア

上位レベルのスコープにアクセスする場合、これは少し異なり、式はすべての引数のJOINです。使用方法:コンテキストデータは次のようになります。

// data
{name: 'Sam', age: '20', address: { city: 'yomomaz' } }

// in template
// notice how the expression wrap all the string with quotes, and even the variables
// as they will become strings by the time they hit the helper
// play with it, you will immediately see the errored expressions and figure it out

{{#with address}}
    {{z '"hi " + "' ../this.name '" + " you live with " + "' city '"' }}
{{/with}}

JavaScript:

Handlebars.registerHelper("z", function () {
    var options = arguments[arguments.length - 1]
    delete arguments[arguments.length - 1];
    return Handlebars.helpers["x"].apply(this, [Array.prototype.slice.call(arguments, 0).join(''), options]);
});

Handlebars.registerHelper("zif", function () {
    var options = arguments[arguments.length - 1]
    delete arguments[arguments.length - 1];
    return Handlebars.helpers["x"].apply(this, [Array.prototype.slice.call(arguments, 0).join(''), options]) ? options.fn(this) : options.inverse(this);
});

15
これは素晴らしい。ハンドルバーは何をすべきかをあなたに伝えることができません:)
レミアント

1
:)ありがとう、私は要点を少し更新して、いくつかの良い点を追加しました(このSOの質問には直接関係ありませんが、ハンドルバーテンプレート内で必要なことを行うという精神で)。ただし、制限に注意する必要があります。 「tは式の中から『上位スコープレベル』にアクセスする方法を発見し、あなたはそれぞれのスコープにしている、と言う{{#each}} ... {{xif ' ../name === this.name' }} {{/each}}...しかし、私はまだ調査しています...
bentael

1
「上位スコープアクセス」の解決策を見つけましたが、新しいヘルパーを使用しました。更新された回答、{{z ...}}ヘルパーを参照してください
ベンタエル14年

ブーム!すばらしいです。これで、部分的な感謝の気持ちを込めて実際の状態を実現できます。
AncAinu 14

1
@rickysullivan eval(expression);をこれに置き換えてみてください:eval('(function(){try{return ' + expression + ';}catch(e){}})();');-これは醜くなっていることはわかっていますが、これを行う安全な方法は考えられません-これは実行するのが非常に「速く」ないので注意してください。巨大な反復。
ベンタエル2016年

33

ヘルパー関数を記述せずにこれを行う簡単な方法があります...テンプレート内で完全に実行できます。

{{#if cond1}}   
  {{#if con2}}   
    <div> and condition completed</div>  
  {{/if}}
{{else}}   
  <div> both conditions weren't true</div>  
{{/if}}

編集:逆に、これを行うことでor'sを行うことができます:

{{#if cond1}}  
  <div> or condition completed</div>    
{{else}}   
  {{#if cond2}}  
    <div> or condition completed</div>  
  {{else}}      
    <div> neither of the conditions were true</div>    
  {{/if}}  
{{/if}}

編集/メモ:ハンドルバーのウェブサイト:handlebarsjs.comから、ここに偽の値があります:

ifヘルパーを使用して、条件付きでブロックをレンダリングできます。引数がfalse、未定義、null、 ""または[](「偽」の値)を返す場合、「cond」(cond1やcond2など)はtrueとしてカウントされません。


9
実際には、2つの値を比較するのではなく、両方が存在することを確認するだけです。それは異なります。
Cyril N.

3
実際には、ウェブサイトからjavascriptと同じ方法で評価されます。ハンドルバーはブロックをレンダリングしません。」
Jono

1
あなたが正しい、私は最初にテストが2つの値を比較することであり、両方のテストが存在することではないと思った。すみません。
Cyril N.

4
これは正しく動作しません。cond1がtrueでcon2がfalseの場合、何も出力されません。
Tessa Lau

1
@TessaLauさん、こんにちは。ただし、制御フローを引き出すと、最初の行で制御フローがその条件に移動することがわかります。
Jono

19

ここに掲載されているすべての回答の1つの問題は、バインドされたプロパティでは機能しないことです。つまり、関係するプロパティが変更されたときにif条件が再評価されません。これは、バインディングをサポートするヘルパーのもう少し高度なバージョンです。通常のEmberを実装するためにも使用されるEmberソースからのbind関数を使用します#ifヘルパーの。

これは、右側の定数と比較して、左側の単一のバインドプロパティに制限されています。これは、ほとんどの実用的な目的には十分だと思います。単純な比較よりも高度なものが必要な場合は、いくつかの計算されたプロパティを宣言し、#if代わりに通常のヘルパーを使用することをお勧めします。

Ember.Handlebars.registerHelper('ifeq', function(a, b, options) {
  return Ember.Handlebars.bind.call(options.contexts[0], a, options, true, function(result) {
    return result === b;
  });
});

次のように使用できます。

{{#ifeq obj.some.property "something"}}
  They are equal!
{{/ifeq}}

Emberを使用している場合、これが適切な答えです。あなたが述べた他のソリューションは、値の代わりにキーを渡すだけです。ところでこれに感謝し、数時間頭を悩ませました。
J Lee

2
誰かがこれをHTMLBars / Ember 1.10で動作させていますか?Ember.Handlebars.bindは存在しないようです。
リンダ

それは他の値とバックに変更されない条件を変更したとき、私はもともとこのメソッドは、変更するための残り火で動作します。..もともとが、その後registerBoundHelperを使用:)それはもっとたくさんアップ投票していなければならない
マットVukomanovic

13

基本的に任意のバイナリ演算子で動作する改善されたソリューション(少なくとも数値、文字列はevalではうまく動作しません。ユーザー入力で定義されていない演算子を使用する場合は、可能なスクリプトの注入に注意してください):

Handlebars.registerHelper("ifCond",function(v1,operator,v2,options) {
    switch (operator)
    {
        case "==":
            return (v1==v2)?options.fn(this):options.inverse(this);

        case "!=":
            return (v1!=v2)?options.fn(this):options.inverse(this);

        case "===":
            return (v1===v2)?options.fn(this):options.inverse(this);

        case "!==":
            return (v1!==v2)?options.fn(this):options.inverse(this);

        case "&&":
            return (v1&&v2)?options.fn(this):options.inverse(this);

        case "||":
            return (v1||v2)?options.fn(this):options.inverse(this);

        case "<":
            return (v1<v2)?options.fn(this):options.inverse(this);

        case "<=":
            return (v1<=v2)?options.fn(this):options.inverse(this);

        case ">":
            return (v1>v2)?options.fn(this):options.inverse(this);

        case ">=":
         return (v1>=v2)?options.fn(this):options.inverse(this);

        default:
            return eval(""+v1+operator+v2)?options.fn(this):options.inverse(this);
    }
});

これをテンプレートでどのように使用しますか?特にoptions.fn部分は?
qodeninja 2014

{{ifCond val1 '||' val2}} true {{else}} false {{/ if}}正しい場合はoptions.fn(true、ifCond句)を返し、そうでない場合は正しくない場合はoptions.inverse(false、else句)を返します。
Nick Kitto

1
スクリプトインジェクションについての注意事項のため、このヘルパーを使用しないことを強くお勧めします。大規模なコードベースでは、これはすぐに厄介なセキュリティ問題の原因となる可能性があります
Jordan Sitkin

8

複数の条件を確認する場合の解決策は次のとおりです。

/* Handler to check multiple conditions
   */
  Handlebars.registerHelper('checkIf', function (v1,o1,v2,mainOperator,v3,o2,v4,options) {
      var operators = {
           '==': function(a, b){ return a==b},
           '===': function(a, b){ return a===b},
           '!=': function(a, b){ return a!=b},
           '!==': function(a, b){ return a!==b},
           '<': function(a, b){ return a<b},
           '<=': function(a, b){ return a<=b},
           '>': function(a, b){ return a>b},
           '>=': function(a, b){ return a>=b},
           '&&': function(a, b){ return a&&b},
           '||': function(a, b){ return a||b},
        }
      var a1 = operators[o1](v1,v2);
      var a2 = operators[o2](v3,v4);
      var isTrue = operators[mainOperator](a1, a2);
      return isTrue ? options.fn(this) : options.inverse(this);
  });

使用法:

/* if(list.length>0 && public){}*/

{{#checkIf list.length '>' 0 '&&' public '==' true}} <p>condition satisfied</p>{{/checkIf}}

7

使用するブロックヘルパーへのリンクは次のとおり です。比較ブロックヘルパー。すべての標準演算子をサポートし、以下に示すようにコードを記述できます。とても便利です。

{{#compare Database.Tables.Count ">" 5}}
There are more than 5 tables
{{/compare}}

1
これが落札です。ネイティブおよび意図。たいていの場合、新しいヘルパーを書いていると、それを考えすぎていることに気づきます。
8

2
@auguroneこれはネイティブヘルパーではありません。リンクをクリックすると、カスタム定義されたヘルパーであることがわかります。
gfullam 2015年

@gfullamそうです、私はこのヘルパーをネイティブで含む、アセンブルでハンドルバーを使用していました。私の悪い。
8

4

ジムの答えに似ていますが、少し創造性を使用して、次のようなこともできます。

Handlebars.registerHelper( "compare", function( v1, op, v2, options ) {

  var c = {
    "eq": function( v1, v2 ) {
      return v1 == v2;
    },
    "neq": function( v1, v2 ) {
      return v1 != v2;
    },
    ...
  }

  if( Object.prototype.hasOwnProperty.call( c, op ) ) {
    return c[ op ].call( this, v1, v2 ) ? options.fn( this ) : options.inverse( this );
  }
  return options.inverse( this );
} );

それを使用するには、次のようなものを取得します。

{{#compare numberone "eq" numbretwo}}
  do something
{{else}}
  do something else
{{/compare}}

パフォーマンスを向上させるために、関数からオブジェクトを移動することをお勧めしますが、それ以外の場合は、「and」や「or」など、必要な比較関数を追加できます。


3

もう1つの方法は、関数名をで使用すること#ifです。#ifパラメータは関数であり、それがあるならば、それはそれを呼び出すとtruthynessチェックのために、その戻りを使用するかどうかを検出します。myFunctionの下では、現在のコンテキストがとして取得されthisます。

{{#if myFunction}}
  I'm Happy!
{{/if}}

では、コンテキストに関数を追加する必要がありますか?コードのソースが不明である可能性があるため、コンテキストからコードを実行することはセキュリティホールです。これはXSS攻撃に悪用される可能性があります。
T Nguyen

はい、関数をコンテキストに追加する必要があります。不適切に設計されたWebサイトでは、はい、これはセキュリティホールになる可能性があります。しかし、その場合、他にもたくさんあります。
Shital Shah、

これは推奨される方法です。
elad.chen 2014

3

残念ながら、これらのソリューションはいずれも「OR」演算子「cond1 || cond2」の問題を解決しません。

  1. 最初の値がtrueかどうかを確認します
  2. 「^」(または)を使用し、それ以外の場合はcond2がtrueかどうかを確認します

    {{#if cond1}}アクションを実行する{{^}} {{#if cond2}}アクションを実行する{{/ if}} {{/ if}}

DRYルールに違反します。では、パーシャルを使用して混乱を少なくしてください

{{#if cond1}}
    {{> subTemplate}}
{{^}}
    {{#if cond2}}
        {{> subTemplate}}
    {{/if}}
{{/if}}

3

テンプレート内で実行するさまざまな比較が多数ある状況でヘルパーを作成する理由を理解できますが、比較の数が比較的少ない(または1つでもあるため、このページに移動したのはこのためです)そもそも)、おそらく次のように、ビューレンダリング関数呼び出しで新しいハンドルバー変数を定義する方が簡単でしょう。

レンダリング時にハンドルバーに渡す:

var context= {
    'section1' : section1,
    'section2' : section2,
    'section1or2' : (section1)||(section2)
};

ハンドルバーテンプレート内で:

{{#if section1or2}}
    .. content
{{/if}}

単純化のために、またハンドルバーの論理のない性質に準拠しながら迅速かつ役立つ回答になるため、これについて言及します。


3

以下のコマンドを実行してEmber Truth Helpersアドオン をインストールします

emberインストールember-truth-helpers

ほとんどの論理演算子(eq、not-eq、not、and、or、gt、gte、lt、lte、xor)を使い始めることができます。

{{#if (or section1 section2)}}  
...content  
{{/if}}

さらに進むために部分式を含めることもできます。

{{#if (or (eq section1 "section1") (eq section2 "section2") ) }}  
...content  
{{/if}}

2

三元ヘルパーのさらに別の曲がったソリューション:

'?:' ( condition, first, second ) {
  return condition ? first : second;
}

<span>{{?: fooExists 'found it' 'nope, sorry'}}</span>

または、単純な合体ヘルパー:

'??' ( first, second ) {
  return first ? first : second;
}

<span>{{?? foo bar}}</span>

これらの文字はハンドルバーのマークアップで特別な意味を持たないため、ヘルパー名として自由に使用できます。


1

私は、CoffeeScriptで作成されたnpmパッケージを見つけました。このパッケージには、ハンドルバー用の非常に便利なヘルパーがたくさんあります。次のURLにあるドキュメントをご覧ください。

https://npmjs.org/package/handlebars-helpers

あなたはできる wget http://registry.npmjs.org/handlebars-helpers/-/handlebars-helpers-0.2.6.tgzそれらをダウンロードしてパッケージの内容を見るます。

{{#is number 5}}またはのようなことができるようになります{{formatDate date "%m/%d/%Y"}}


1

どちらか一方の要素が存在するかどうかを確認するだけの場合は、このカスタムヘルパーを使用できます。

Handlebars.registerHelper('if_or', function(elem1, elem2, options) {
  if (Handlebars.Utils.isEmpty(elem1) && Handlebars.Utils.isEmpty(elem2)) {
    return options.inverse(this);
  } else {
    return options.fn(this);
  }
});

このような

{{#if_or elem1 elem2}}
  {{elem1}} or {{elem2}} are present
{{else}}
  not present
{{/if_or}}

関数の戻り値を比較するための「または」も必要な 場合 をは、目的の結果を返す別のプロパティを追加します。

結局のところ、テンプレートはロジックレスでなければなりません!



1

文字列が別の文字列と等しいかどうかを確認する方法についてのグーグル検索からこの投稿に来ました。

私はNodeJSサーバー側でHandlebarsJSを使用していますが、ブラウザバージョンのHandlebarsJSを使用してそれを解析するフロントエンドでも同じテンプレートファイルを使用しています。つまり、カスタムヘルパーが必要な場合は、2つの別々の場所で定義するか、問題のオブジェクトに関数を割り当てる必要があります。

人々が忘れているのは、口ひげテンプレートで使用できる特定のオブジェクトに継承機能があることです。文字列の場合:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/match

An Array containing the entire match result and any parentheses-captured matched results; null if there were no matches.

このメソッドを使用して、一致の配列を返すか、null一致が見つからなかった場合に返すことができます。HandlebarsJSのドキュメントhttp://handlebarsjs.com/builtin_helpers.htmlを見ると、これは完璧です。

You can use the if helper to conditionally render a block. If its argument returns false, undefined, null, "", 0, or [], Handlebars will not render the block.

そう...

{{#if your_string.match "what_youre_looking_for"}} 
String found :)
{{else}}
No match found :(
{{/if}}

更新:

すべてのブラウザでテストした後、これはFirefoxでは機能しません。HandlebarsJSは他の引数を関数呼び出しに渡します。つまり、String.prototype.matchが呼び出されると、2番目の引数(つまり、上記のドキュメントに記載されているmatch関数呼び出しのRegexpフラグ)が渡されているように見えます。FirefoxはこれをString.prototype.matchの非推奨の使用と見なしているため、機能しません。

回避策は、String JSオブジェクトの新しい機能プロトタイプを宣言し、代わりにそれを使用することです。

if(typeof String.includes !== 'function') {
    String.prototype.includes = function(str) {
        if(!(str instanceof RegExp))
            str = new RegExp((str+'').escapeRegExp(),'g');
        return str.test(this);
    }
}

Handlebars.compile()関数を実行する前に、このJSコードが含まれていることを確認してから、テンプレートで...

{{#your_string}}
    {{#if (includes "what_youre_looking_for")}} 
        String found :)
    {{else}}
        No match found :(
    {{/if}}
{{/your_string}}

Firefox用に更新されました。これは私が現在使用しているものです
Jon

1

ここには、複数の論理&&および||のバニラハンドルバーがあります。(およびまたは):

Handlebars.registerHelper("and",function() {
    var args = Array.prototype.slice.call(arguments);
    var options = args[args.length-1];

    for(var i=0; i<args.length-1; i++){
        if( !args[i] ){
            return options.inverse(this);
        }
    }

    return options.fn(this);
});


Handlebars.registerHelper("or",function() {
    var args = Array.prototype.slice.call(arguments);
    var options = args[args.length-1];

    for(var i=0; i<args.length-1; i++){
        if( args[i] ){
            return options.fn(this);
        }
    }

    return options.inverse(this);
}

// Results
// {{#and foo bar sally bob}} yup {{else}} nope {{/and}} // yup
// {{#or foo bar "" sally bob}} yup {{else}} nope {{/or}} // yup

// {{#and foo bar "" sally bob}} yup {{else}} nope {{/and}} // nope
// {{#or "" "" "" "" ""}} yup {{else}} nope {{/or}} // nope

「and」と「or」を使用しても「安全」かどうかわからない...「op_and」や「op_or」のようなものに変更するかもしれませんか?


1

AND / ORの正しい解決策

Handlebars.registerHelper('and', function () {
    // Get function args and remove last one (function name)
    return Array.prototype.slice.call(arguments, 0, arguments.length - 1).every(Boolean);
});
Handlebars.registerHelper('or', function () {
    // Get function args and remove last one (function name)
    return Array.prototype.slice.call(arguments, 0, arguments.length - 1).some(Boolean);
}); 

次に、次のように呼び出します

{{#if (or (eq questionType 'STARTTIME') (eq questionType 'ENDTIME') (..) ) }}

ところで:ここで与えられた解は正しくないことに注意してください、彼は関数名である最後の引数を差し引いていません。 https://stackoverflow.com/a/31632215/1005607

彼の元のAND / ORは引数の完全なリストに基づいていました

   and: function () {
        return Array.prototype.slice.call(arguments).every(Boolean);
    },
    or: function () {
        return Array.prototype.slice.call(arguments).some(Boolean);
    }

誰かがその答えを変更できますか?86人が推奨する回答で何かを修正しようとして1時間無駄にしただけです。修正は、関数名である最後の引数を除外することです。Array.prototype.slice.call(arguments, 0, arguments.length - 1)


0

これらの2つのガイドa-way-to-let-users-define-custom-made-bound-if-statementsおよびカスタムバインドヘルパーに従って、標準の代わりにこれを使用するように、stackoverflowのこの投稿で共有ビューを調整することができました# ifステートメント。これは、#ifをそこに投げるだけの場合よりも安全です。

その要点のカスタムバインドされたヘルパーは優れています。

<li>
    <a href="{{unbound view.varProductSocialBlog}}">
        {{#if-equal view.showDiv "true"}}<div>{{/if-equal}}<i class="fa fa-rss-square"></i>{{#if-equal view.showDiv "true"}}</div>{{/if-equal}}
        {{#if-equal view.showTitle "true"}}Blog{{/if-equal}}
    </a>
</li>

私はエンバークリを使用しています私の燃えさしのアプリケーションを構築するためのプロジェクトを。

この投稿時の現在のセットアップ:

DEBUG: -------------------------------
DEBUG: Ember      : 1.5.1
DEBUG: Ember Data : 1.0.0-beta.7+canary.b45e23ba
DEBUG: Handlebars : 1.3.0
DEBUG: jQuery     : 2.1.1
DEBUG: -------------------------------

0

Ember.js では、ifブロックヘルパーでインラインifヘルパーを使用できます。||論理演算子を置き換えることができます。次に例を示します。

{{#if (if firstCondition firstCondition secondCondition)}}
  (firstCondition || (or) secondCondition) === true
{{/if}}

0

これは、以下に示すような論理演算子を使用するだけで実行できます。

{{#if (or(eq firstValue 'String_to_compare_value') (eq secondValue 'String_to_compare_value'))}}business logic goes here{{/if}}

{{#if (and(eq firstValue 'String_to_compare_value') (eq secondValue 'String_to_compare_value'))}}business logic goes here{{/if}}

ビジネスロジックを記述できる場合は、閉じる前


0

次のコードを使用できます。

{{#if selection1}}
    doSomething1
{{else}}
   {{#if selection2}}
       doSomething2
   {{/if}}
{{/if}}

あなたの考えやプロセスについて詳しく説明してください。人々が文脈を知らないか、言語に慣れていない場合、人々があなたの解決策を理解するのは非常に難しい場合があります。
mrhn

-1

以下は、ember 1.10とember-cli 2.0に使用しているアプローチです。

// app/helpers/js-x.js
export default Ember.HTMLBars.makeBoundHelper(function (params) {
  var paramNames = params.slice(1).map(function(val, idx) { return "p" + idx; });
  var func = Function.apply(this, paramNames.concat("return " + params[0] + ";"))
  return func.apply(params[1] === undefined ? this : params[1], params.slice(1));
});

その後、次のようにテンプレートで使用できます。

// used as sub-expression
{{#each item in model}}
  {{#if (js-x "this.section1 || this.section2" item)}}
  {{/if}}
{{/each}}

// used normally
{{js-x "p0 || p1" model.name model.offer.name}}

表現の引数は次のように渡される場合はp0p1p2などとp0もとして参照することができますthis

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.