handlebars.js {{#if}}中的逻辑运算符


479

handlebars JS中是否可以将逻辑运算符合并到标准handlebars.js条件运算符中?像这样:

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

我知道我可以写我自己的助手,但是首先我想确保我不会重新发明轮子。

Answers:


518

这可以通过与辅助助手“作弊”来实现。这可能与开发把手的人的思想背道而驰。

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
这确实违反了车把/小胡子的无逻辑性,但是仍然非常有用,谢谢!
巴拉·克拉克

6
请注意,这根本不适用于绑定属性(读取,Ember绑定)。它可以使用文字值,但不能解析模型属性(已通过Ember 1.0.0-rc.8和Handlebars 1.0.0测试),并且registerBoundHelper无法处理Handlebars语法。解决方法是创建一个自定义视图:stackoverflow.com/questions/18005111/...
沃伦·塞纳

28
@BalaClark真的没有逻辑吗?我的意思是,它仍然具有“ if”语句-仅因为它们被故意残废而不会改变哲学。
phreakhead 2014年

111
我从来不明白为什么开发人员喜欢让自己失望。
2014年

36
我不明白为什么AND / OR不能成为Handlebars的一部分。这并没有违反无逻辑的本质,因为已经有了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
不要忘记'||''&&'。我添加了这些案例,它们非常有用。
杰森

20
作为把手的菜鸟,目前尚不清楚的一件事是,您必须将运算符作为字符串传递,否则编译器在标记模板时会出错。{{#ifCond true'=='false}}
Joe Holloway

2
我发现没有为对象属性评估值。添加以下帮助 v1 = Ember.Handlebars.get(this, v1, options) v2 = Ember.Handlebars.get(this, v2, options)
ZX12R

4
但是如果v1和v2也是一种情况,那我该如何使用?例如:if(value ==“ a” || value ==“ b”)
克里希纳

3
如果这样做,你还能做别的吗?
jbyrd

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,2015年

25
我们似乎已经将Lisp内置到车把中。
jdunning

8
andor助手仅使用2个参数,这不是您想要的。我设法重新处理了andor帮助程序,以支持两个以上的参数。将此单线用于andreturn Array.prototype.slice.call(arguments, 0, arguments.length - 1).every(Boolean);并将此单线用于orreturn Array.prototype.slice.call(arguments, 0, arguments.length - 1).some(Boolean);
路加福音

3
一个更先进一点的版本,可以采取对每个运营商多个参数。
Nate

87

对于那些生活在边缘的人来说,这是一个不错的选择。

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

车把帮手: {{#xif EXPRESSION}} {{else}} {{/xif}}

一个可以执行带有任何表达式的IF语句的助手

  1. EXPRESSION是正确转义的字符串
  2. 是的,您需要适当地转义字符串文字或仅替换单引号和双引号
  3. 您可以访问任何全局函数或属性,即 encodeURIComponent(property)
  4. 这个例子假设你传递这方面你的车把template( {name: 'Sam', age: '20' } ),通知agestring,只是这样我就可以演示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. 本示例假定您将此上下文传递到了handlebars template( {name: 'Sam', age: '20' } ),这agestring出于演示目的,可以是任何对象。

用法:

<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 ...}}帮助程序
bentael 2014年

OM!太棒了,现在我可以在部分感谢做真实的事情了!
AncAinu 2014年

1
@rickysullivan尝试eval(expression);用以下代码替换您的代码:eval('(function(){try{return ' + expression + ';}catch(e){}})();');-我知道这越来越难看,但想不出一种安全的方法来执行此操作-请注意,这执行起来不是很“快速”,我不会这样做巨大的迭代。
bentael

33

有一种简单的方法无需编写辅助函数即可完成此操作...可以完全在模板中完成。

{{#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”值),则任何“ cond”(如cond1或cond2)都不会被视为true。


9
并非如此,您不比较两个值,只是确保两个值都存在,这是不同的。
西里尔N.

3
实际上,它从网站上以与javascript相同的方式对其进行评估:“您可以使用if助手来有条件地呈现块。如果其参数返回false,undefined,null,“”或[](“ falsy”值),把手不会渲染该块。”
Jono 2013年

1
没错,我首先认为测试是比较两个值,而不是同时测试两个值。我不好,对不起。
西里尔N.13年

4
这不能正常工作。如果cond1为true而con2为false,则不会打印任何内容。
泰莎·劳

1
嘿@TessaLau,我想我知道您来自哪里。但是,如果绘制出控制流,则会在第一行看到将控制流移至该状态。
乔诺2014年

19

这里发布的所有答案的一个问题是它们不适用于绑定的属性,即,当涉及的属性发生更改时,if条件不会重新评估。这是支持绑定的助手的稍微高级的版本。它使用Ember源中的bind函数,该函数还用于实现常规的Ember #ifhelper。

与右侧的常量相比,此常量仅限于左侧的单一绑定属性,我认为这对于大多数实际目的而言已经足够。如果您需要比简单比较更高级的功能,那么最好开始声明一些计算的属性并改用常规的#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最初但是当它改变状态不会更改为其他值和背部。这与Ember方法适用于改变:)它应该有更多的票了
马特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}}真{{else}}假{{/ if}},如果正确,则返回options.fn(true,ifCond子句),否则返回options.inverse(false,else子句)。
尼克·基托2014年

1
由于提到了有关脚本注入的警告,因此我强烈建议您不要使用此助手。在大型代码库中,这很容易导致严重的安全问题
Jordan Sitkin 2014年

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
这应该是获胜的选票。本机和预期的。我几乎每次都发现,如果您正在编写一个新的帮助程序,那么您会认为它过分了。
augurone

2
@augurone这不是本地帮手。如果您点击链接,您将看到它是一个自定义的帮助器。
gfullam 2015年

@gfullam,您是对的,我在汇编中使用了车把,它本身就包含了此帮助器。我的错。
augurone

4

与Jim的答案类似,但是通过使用一些创造力,我们还可以执行以下操作:

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

另一种选择是在中使用函数名称#if。在#if将检测的参数功能,如果是那么它会调用它,利用它truthyness检查的回报。在myFunction下面,获取当前上下文为this

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

因此,您需要在上下文中添加一个函数?从上下文执行代码是一个安全漏洞,因为代码的来源可能是未知的。可以将其用于XSS攻击。
T Nguyen

是的,您需要在上下文中添加功能。是的,在设计不良的网站中,这可能是安全漏洞。但是在那种情况下,将会有许多其他情况。
Shital Shah 2013年

这是首选方式。
elad.chen 2014年

3

不幸的是,这些解决方案都不能解决“ OR”运算符“ cond1 || cond2”的问题。

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

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

它违反了DRY规则。那么为什么不使用partial来减少混乱

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

3

我能理解为什么您要为模板中有大量要执行的各种比较的情况创建助手,而对于比较少的比较(甚至是一个比较,这就是使我进入此页面的原因)的原因首先),在视图渲染函数调用中定义新的handlebars变量可能会更容易,例如:

传递给渲染的车把:

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

然后在您的车把模板中:

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

我之所以这么简单是为了简单起见,也是因为它是一个快速而有用的答案,同时仍然符合Handlebars的无逻辑本质。


3

通过运行以下命令来安装Ember Truth Helpers插件

余烬安装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}}

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

如果您只想检查一个或另一个元素是否存在,则可以使用此自定义帮助器

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

刚刚从Google搜索中找到有关如何检查一个字符串是否等于另一个字符串的帖子。

我在NodeJS服务器端使用HandlebarsJS,但是我也使用浏览器版本的HandlebarsJS在前端使用相同的模板文件进行解析。这意味着,如果我想要一个自定义帮助程序,则必须在2个不同的地方定义它,或者为有问题的对象分配一个功能-太费力了!

人们忘记的是某些对象具有可在小胡子模板中使用的继承功能。如果是字符串:

https://developer.mozilla.org/zh-CN/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时,似乎正在传递第二个参数(即,根据上述文档,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个人推荐的答案中的某些内容。解决方法是过滤掉最后一个参数,即函数名。Array.prototype.slice.call(arguments, 0, arguments.length - 1)


0

按照这两个指南,让用户定义自定义绑定if语句自定义绑定帮助器,我能够在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>

我正在使用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: -------------------------------

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.