標準のhandlebars.js条件付き演算子に論理演算子を組み込むためのハンドルバーJSの方法はありますか?このようなもの:
{{#if section1 || section2}}
.. content
{{/if}}
私は自分のヘルパーを書くことができることを知っています、しかし最初に私は私が車輪を再発明しないことを確かめたいと思います。
これはブロックヘルパーで「だまし」をすることで可能になります。これはおそらくハンドルバーを開発した人々のイデオロギーに反するものです。
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}}
解決策をさらに一歩進めます。これは比較演算子を追加します。
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}}
コーヒースクリプト版
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
ハンドルバーは入れ子になった操作をサポートします。ロジックを少し違った方法で書くと、これによって多くの柔軟性(およびよりクリーンなコード)が得られます。
{{#if (or section1 section2)}}
.. content
{{/if}}
実際、あらゆる種類のロジックを追加できます。
{{#if (or
(eq section1 "foo")
(ne section2 "bar"))}}
.. content
{{/if}}
これらのヘルパーを登録するだけです。
Handlebars.registerHelper({
eq: function (v1, v2) {
return v1 === v2;
},
ne: function (v1, v2) {
return v1 !== v2;
},
lt: function (v1, v2) {
return v1 < v2;
},
gt: function (v1, v2) {
return v1 > v2;
},
lte: function (v1, v2) {
return v1 <= v2;
},
gte: function (v1, v2) {
return v1 >= v2;
},
and: function () {
return Array.prototype.slice.call(arguments).every(Boolean);
},
or: function () {
return Array.prototype.slice.call(arguments, 0, -1).some(Boolean);
}
});
エッジに住んでいるあなたの人々のために、これをノッチにしてください。
Gist: https://Gist.github.com/akhoury/9118682デモ:以下のコードスニペット
{{#xif EXPRESSION}} {{else}} {{/xif}}
encodeURIComponent(property)
template( {name: 'Sam', age: '20' } )
に渡したと仮定しています。age
はstring
です。これは、この記事の後半でparseInt()
をデモできるようにするためです。<p>
{{#xif " name == 'Sam' && age === '12' " }}
BOOM
{{else}}
BAMM
{{/xif}}
</p>
<p>
BOOM
</p>
Handlebars.registerHelper("xif", function (expression, options) {
return Handlebars.helpers["x"].apply(this, [expression, options]) ? options.fn(this) : options.inverse(this);
});
{{x EXPRESSION}}
parseInt(property)
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>
わかりやすくするために構文を拡張し、ほぼ各行についてコメントしたので、これは少し大きく見えます。
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: '[email protected]'
}, {
firstName: 'Sam',
age: '18',
email: '[email protected]'
}, {
firstName: 'Perter',
lastName: 'Smith',
age: '25',
email: '[email protected]'
}];
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}}
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);
});
ヘルパー関数を書かずにこれを行う簡単な方法があります...それはテンプレート内で完全に行うことができます。
{{#if cond1}}
{{#if con2}}
<div> and condition completed</div>
{{/if}}
{{else}}
<div> both conditions weren't true</div>
{{/if}}
編集:逆にこれを行うことで行うことができますかの:
{{#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、undefined、null、 ""、または[]( "falsy"値)を返した場合、(cond1やcond2のような) 'cond'はtrueとしてカウントされません。
ここに掲載されているすべての回答に伴う1つの問題は、それらがバウンドプロパティでは動作しないことです。これは、バインディングをサポートする、もう少し高度なバージョンのヘルパーです。 Emberソースの bind 関数を使います。これは通常のEmber #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}}
基本的に任意の二項演算子で動作する改善された解決策(少なくとも数字、文字列は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);
}
});
これが私が使っているブロックヘルパーへのリンクです: 比較ブロックヘルパー 。これはすべての標準的な演算子をサポートしており、以下に示すようにコードを書くことができます。とても便利です。
{{#compare Database.Tables.Count ">" 5}}
There are more than 5 tables
{{/compare}}
あなたが複数の条件をチェックしたいならば、これは解決策です:
/* 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}}
ジムの答えに似ていますが、少し創造力を使うことで、次のようなこともできます。
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"など、必要な比較関数を追加できます。
もう1つの選択肢は、#if
で関数名を使用することです。 #if
は、パラメータがfunctionかどうかを検出し、そうであればそれを呼び出して真偽チェックのためにその戻り値を使用します。以下のmyFunctionは現在のコンテキストをthis
として取得します。
{{#if myFunction}}
I'm Happy!
{{/if}}
以下のコマンドを実行して、 Ember Truth Helpers addonをインストールします。
emberインストールember-truth-helpers
ほとんどの論理演算子(eq、not-eq、not、and、gt、gte、lt、lte、xor)を使い始めることができます。
{{#if (or section1 section2)}}
...content
{{/if}}
さらに進むために部分式を含めることもできます。
{{#if (or (eq section1 "section1") (eq section2 "section2") ) }}
...content
{{/if}}
テンプレート内でさまざまな種類の比較を実行する必要がある状況で、比較的少数の比較(または1つの場合でもこのため、このページに表示されたもの)に対してヘルパーを作成する理由を理解できます。まず第一に、ビューレンダリング関数呼び出しで新しいhandlebars変数を定義するほうがおそらく簡単でしょう。
レンダリング時にハンドルバーに渡す:
var context= {
'section1' : section1,
'section2' : section2,
'section1or2' : (section1)||(section2)
};
そして、あなたのハンドルバーテンプレートの中で:
{{#if section1or2}}
.. content
{{/if}}
私はこれを単純さのために述べています、そしてそれはHandlebarsの論理的な性質を依然として遵守しながら迅速かつ有用であるかもしれない答えでもあるので。
どちらかの要素が存在するかどうかだけを確認したい場合は、このカスタムヘルパーを使用できます。
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}}
比較するために "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)
ここに複数の論理的な&&と||のためのVanillaハンドルバーがあります。 (およびまたは):
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"のように変更してください。
私は、HandScriptのための信じられないほど便利なヘルパーがたくさんある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"}}
のようなことができるようになります
オブジェクトのプロパティを比較するのに問題がある人のために、ヘルパーの中にこのソリューションを追加してください
残念ながら、これらの解決法のどれも「OR」演算子「cond1 || cond2」の問題を解決しません。
"^"(または)を使用して、それ以外の場合はcond2がtrueかどうかを確認してください。
{{#if cond1}}行動を起こします{{^}} {{#if cond2}}行動を起こします{{/ if}} {{/ if}}
DRY規則に違反します。それでは、それほど煩雑でないようにpartialを使用しないでください。
{{#if cond1}}
{{> subTemplate}}
{{^}}
{{#if cond2}}
{{> subTemplate}}
{{/if}}
{{/if}}
文字列が別の文字列と等しいかどうかを確認する方法についてのグーグル検索からこの記事に来ました。
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);
}
}
このJSコードが含まれていることを確認してください before あなたはあなたのHandlebars.compile()関数を実行し、そしてあなたのテンプレートで...
{{#your_string}}
{{#if (includes "what_youre_looking_for")}}
String found :)
{{else}}
No match found :(
{{/if}}
{{/your_string}}
三項ヘルパーのためのさらに別の曲がった解決策:
'?:' ( condition, first, second ) {
return condition ? first : second;
}
<span>{{?: fooExists 'found it' 'nope, sorry'}}</span>
または単純な合体ヘルパー:
'??' ( first, second ) {
return first ? first : second;
}
<span>{{?? foo bar}}</span>
これらの文字はハンドルバーマークアップで特別な意味を持たないので、あなたは自由にそれらをヘルパー名のために使うことができます。
Ember.jsでは、 インラインif helper in ifブロックヘルパーを使用できます。 ||
論理演算子を置き換えることができます。次に例を示します。
{{#if (if firstCondition firstCondition secondCondition)}}
(firstCondition || (or) secondCondition) === true
{{/if}}
以下に示すように、単純に論理演算子を使用してそれを行うことができます。
{{#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}}
あなたがあなたのビジネスロジックを書くことができるならば、閉じる前に
これら2つのガイドに従って、 ユーザー定義の定義 - カスタムif-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>
私は ember cli プロジェクトを使って私のemberアプリケーションをビルドしています。
この記事の時点での現在の設定:
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: -------------------------------