在handlebars.js {{#if}}条件下的逻辑运算符

有没有在句柄JS的方法将逻辑运算符合并到标准的handlebars.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 

为了那些生活在边缘的人们,把这个问题提高一点。

要点 : https : //gist.github.com/akhoury/9118682 演示 :下面的代码片段

{{#xif EXPRESSION}} {{else}} {{/xif}}助手: {{#xif EXPRESSION}} {{else}} {{/xif}}

用任何表达式执行IF语句的助手

  1. EXPRESSION是一个正确转义的字符串
  2. 是的,你需要正确地逃避字符串文字或只是交替单引号和双引号
  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. 是的,你需要正确地逃避字符串文字或只是交替单引号和双引号
  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> 

把手支持嵌套操作。 如果我们写逻辑有点不同,这提供了很大的灵活性(和更简洁的代码)。

 {{#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 (v1, v2) { return v1 && v2; }, or: function (v1, v2) { return v1 || v2; } }); 

有一个简单的方法来做这个,而不用编写一个辅助函数…它可以在模板内完成。

 {{#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这里是falsy值:

你可以使用if助手来有条件地渲染一个块。 如果它的参数返回false,undefined,null,“”或[](一个“falsy”值),那么任何'cond'(如cond1或cond2)都不会被计为true。

这里发布的所有答案的一个问题是,它们不能与绑定的属性一起工作,也就是说,当所涉及的属性改变时,if条件不被重新评估。 这是帮助程序支持绑定的稍微更高级的版本。 它使用来自Ember源的绑定函数,也用于实现普通的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}} 

类似于吉姆的答案,但是使用一点创造力,我们也可以做这样的事情:

 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”。

另一种方法是在#if使用函数名称。 #if会检测参数是否为函数,如果是,则会调用它并使用它的返回进行真实性检查。 在myFunction下方获取当前上下文。

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

通过运行下面的命令来安装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}} 

我可以理解你为什么要创建一个帮助器,你需要在你的模板中执行大量不同的比较操作,但是要进行相对少量的比较(或者甚至是一个,这就是我带到这个页面的原因第一个地方),在视图渲染函数调用中定义一个新的handlebars变量可能会更容易一些,如:

通过渲染上的句柄:

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

然后在你的句柄模板中:

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

我提到这是为了简单起见,也是因为这个答案可能是快速而有益的,同时仍然符合把手的逻辑性。

这是一个解决方案,如果你想检查多个条件:

 /* 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}} 

我找到了一个用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"}}

如果你只是想检查一个或其他元素是否存在,你可以使用这个自定义帮助器

 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”操作符“cond1 || cond2”的问题。

  1. 检查第一个值是否为真
  2. 使用“^”(或)并检查cond2是否为true

    {{#if cond1}}行动{{^}} {{#if cond2}}行动{{/ if}} {{/ if}}

它打破了DRY规则。 那么为什么不使用偏好来减少杂乱

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

对于那些比较对象属性有问题的人来说,在助手里面添加这个解决方案

Ember.js帮手没有正确识别一个参数

在这里,我们有多个逻辑&&和||的香草把手 (和或):

 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.fn(this); } } return options.inverse(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”之类的东西?

刚刚从谷歌搜索这个职位,如何检查一个字符串是否等于另一个字符串。

我在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时,第二个参数(即按照上述文档调用匹配函数的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}} 

遵循这两个指南a-way-to-let-users-define-custom-made-bound-if-statements和自定义绑定帮助程序我能够调整我的共享视图在这个帖子在stackoverflow使用这个,而不是标准#如果声明。 这应该比在那里抛一个#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> 

我正在使用的呃cli项目来建立我的烬应用程序。

当前在这篇文章中的设置:

 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: ------------------------------- 

在Ember.js中, 如果帮助程序中有助手 ,可以使用内联 。 它可以代替|| 逻辑运算符,例如:

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

关闭之前,如果你可以写你的业务逻辑

这里有一个我使用的用于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}} 

如果表达式的参数作为p0传入,则p1p2等和p0也可以被引用。