Javascript handlebars.js {{#if}} 条件中的逻辑运算符
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8853396/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Logical operator in a handlebars.js {{#if}} conditional
提问by Mike Robinson
Is there a way in handlebars JS to incorporate logical operators into the standard handlebars.js conditional operator? Something like this:
在handlebars JS 中有没有办法将逻辑运算符合并到标准handlebars.js 条件运算符中?像这样的东西:
{{#if section1 || section2}}
.. content
{{/if}}
I know I could write my own helper, but first I'd like to make sure I'm not reinventing the wheel.
我知道我可以编写自己的助手,但首先我想确保我没有重新发明轮子。
回答by Nick Kitto
This is possible by 'cheating' with a block helper. This probably goes against the Ideology of the people who developed Handlebars.
这可以通过使用块助手“作弊”来实现。这可能与开发 Handlebars 的人的意识形态背道而驰。
Handlebars.registerHelper('ifCond', function(v1, v2, options) {
if(v1 === v2) {
return options.fn(this);
}
return options.inverse(this);
});
You can then call the helper in the template like this
然后您可以像这样调用模板中的助手
{{#ifCond v1 v2}}
{{v1}} is equal to {{v2}}
{{else}}
{{v1}} is not equal to {{v2}}
{{/ifCond}}
回答by Jim
Taking the solution one step further. This adds the compare operator.
将解决方案更进一步。这添加了比较运算符。
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);
}
});
Use it in a template like this:
在这样的模板中使用它:
{{#ifCond var1 '==' var2}}
Coffee Script version
咖啡脚本版本
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
回答by kevlened
Handlebars supports nested operations. This provides a lot of flexibility (and cleaner code) if we write our logic a little differently.
Handlebars 支持嵌套操作。如果我们以稍微不同的方式编写我们的逻辑,这会提供很大的灵活性(和更清晰的代码)。
{{#if (or section1 section2)}}
.. content
{{/if}}
In fact, we can add all sorts of logic:
其实我们可以添加各种逻辑:
{{#if (or
(eq section1 "foo")
(ne section2 "bar"))}}
.. content
{{/if}}
Just register these helpers:
只需注册这些助手:
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);
}
});
回答by bentael
taking this one up a notch, for those of you who live on the edge.
对于那些生活在边缘的人来说,把这个提升一个档次。
gist: https://gist.github.com/akhoury/9118682Demo: Code snippet below
要点:https: //gist.github.com/akhoury/9118682演示:下面的代码片段
Handlebars Helper: {{#xif EXPRESSION}} {{else}} {{/xif}}
车把助手: {{#xif EXPRESSION}} {{else}} {{/xif}}
a helper to execute an IF statement with any expression
使用任何表达式执行 IF 语句的助手
- EXPRESSION is a properly escaped String
- Yes you NEEDto properly escape the string literals or just alternate single and double quotes
- you can access any global function or property i.e.
encodeURIComponent(property)
- this example assumes you passed this context to your handlebars
template( {name: 'Sam', age: '20' } )
, noticeage
is astring
, just for so I can demoparseInt()
later in this post
- EXPRESSION 是一个正确转义的字符串
- 是的,您需要正确转义字符串文字或仅交替使用单引号和双引号
- 您可以访问任何全局函数或属性,即
encodeURIComponent(property)
- 这个例子假设你把这个上下文传递给你的把手
template( {name: 'Sam', age: '20' } )
,注意age
是一个string
,只是为了我可以parseInt()
在这篇文章的后面进行演示
Usage:
用法:
<p>
{{#xif " name == 'Sam' && age === '12' " }}
BOOM
{{else}}
BAMM
{{/xif}}
</p>
Output
输出
<p>
BOOM
</p>
JavaScript: (it depends on another helper- keep reading)
JavaScript:(这取决于另一个助手-继续阅读)
Handlebars.registerHelper("xif", function (expression, options) {
return Handlebars.helpers["x"].apply(this, [expression, options]) ? options.fn(this) : options.inverse(this);
});
Handlebars Helper: {{x EXPRESSION}}
车把助手: {{x EXPRESSION}}
A helper to execute javascript expressions
执行javascript表达式的助手
- EXPRESSION is a properly escaped String
- Yes you NEEDto properly escape the string literals or just alternate single and double quotes
- you can access any global function or property i.e.
parseInt(property)
- this example assumes you passed this context to your handlebars
template( {name: 'Sam', age: '20' } )
,age
is astring
for demo purpose, it can be anything..
- EXPRESSION 是一个正确转义的字符串
- 是的,您需要正确转义字符串文字或仅交替使用单引号和双引号
- 您可以访问任何全局函数或属性,即
parseInt(property)
- 这个例子假设你将此上下文传递给你的把手
template( {name: 'Sam', age: '20' } )
,这age
是一个string
演示目的,它可以是任何东西..
Usage:
用法:
<p>Url: {{x "'hi' + name + ', ' + window.location.href + ' <---- this is your href,' + ' your Age is:' + parseInt(this.age, 10)"}}</p>
Output:
输出:
<p>Url: hi Sam, http://example.com <---- this is your href, your Age is: 20</p>
JavaScript:
JavaScript:
This looks a little large because I expanded syntax and commented over almost each line for clarity purposes
这看起来有点大,因为为了清晰起见,我扩展了语法并注释了几乎每一行
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>
Moar
摩尔
if you want access upper level scope, this one is slightly different, the expression is the JOIN of all arguments, usage: say context data looks like this:
如果你想访问上层范围,这个略有不同,表达式是所有参数的 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:
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);
});
回答by Jono
There is a simple way of doing this without writing a helper function... It can be done within the template completely.
有一种简单的方法可以在不编写辅助函数的情况下执行此操作......它可以完全在模板内完成。
{{#if cond1}}
{{#if con2}}
<div> and condition completed</div>
{{/if}}
{{else}}
<div> both conditions weren't true</div>
{{/if}}
Edit: Conversely you can do or's by doing this:
编辑:相反,您可以通过执行以下操作来执行或操作:
{{#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}}
Edit/Note: From the handlebar's website: handlebarsjs.com here are the falsy values:
编辑/注意:从把手的网站:handlebarsjs.com 这里是虚假值:
You can use the if helper to conditionally render a block. If its argument returns false, undefined, null, "" or [] (a "falsy" value), Then any 'cond' (like cond1 or cond2) will not be counted as true.
您可以使用 if 帮助器有条件地渲染块。如果其参数返回 false、undefined、null、"" 或 [](“falsy”值),则任何“cond”(如 cond1 或 cond2)都不会被视为真。
回答by devongovett
One problem with all of the answers posted here is that they don't work with bound properties, i.e. the if condition is not re-evaluated when the properties involved change. Here's a slightly more advanced version of the helper supporting bindings. It uses the bindfunction from the Ember source, which is also used to implement the normal Ember #if
helper.
此处发布的所有答案的一个问题是它们不适用于绑定属性,即当所涉及的属性发生更改时不会重新评估 if 条件。这是支持绑定的助手的稍微高级的版本。它使用来自 Ember 源代码的bind函数,该函数也用于实现普通的 Ember#if
助手。
This one is limited to a single bound property on the left-hand side, comparing to a constant on the right-hand side, which I think is good enough for most practical purposes. If you need something more advanced than a simple comparison, then perhaps it would be good to start declaring some computed properties and using the normal #if
helper instead.
与右侧的常量相比,这个仅限于左侧的单个绑定属性,我认为这对于大多数实际用途来说已经足够了。如果您需要比简单比较更高级的东西,那么开始声明一些计算属性并使用普通#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;
});
});
You can use it like this:
你可以这样使用它:
{{#ifeq obj.some.property "something"}}
They are equal!
{{/ifeq}}
回答by Vincent
Improved solution that basically work with any binary operator (at least numbers, strings doesn't work well with eval, TAKE CARE OF POSSIBLE SCRIPT INJECTION IF USING A NON DEFINED OPERATOR WITH USER INPUTS):
改进的解决方案基本上适用于任何二元运算符(至少数字、字符串不适用于 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);
}
});
回答by CleanTheRuck
Here's a link to the block helper I use: comparison block helper. It supports all the standard operators and lets you write code as shown below. It's really quite handy.
这是我使用的块助手的链接: 比较块助手。它支持所有标准运算符,并允许您编写如下所示的代码。这真的很方便。
{{#compare Database.Tables.Count ">" 5}}
There are more than 5 tables
{{/compare}}
回答by Sateesh Kumar Alli
Here's a solution if you want to check multiple conditions:
如果您想检查多个条件,这是一个解决方案:
/* 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);
});
Usage:
用法:
/* if(list.length>0 && public){}*/
{{#checkIf list.length '>' 0 '&&' public '==' true}} <p>condition satisfied</p>{{/checkIf}}
回答by ars265
Similar to Jim's answer but a using a bit of creativity we could also do something like this:
类似于吉姆的回答,但使用一点创造力,我们也可以做这样的事情:
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 );
} );
Then to use it we get something like:
然后使用它,我们得到类似的东西:
{{#compare numberone "eq" numbretwo}}
do something
{{else}}
do something else
{{/compare}}
I would suggest moving the object out of the function for better performance but otherwise you can add any compare function you want, including "and" and "or".
我建议将对象移出函数以获得更好的性能,否则您可以添加所需的任何比较函数,包括“and”和“or”。