handlebars.js {{#if}}中的逻辑运算符是有条件的

Mik*_*son 467 javascript handlebars.js

在把手JS中是否有办法将逻辑运算符合并到标准handlebars.js条件运算符中?像这样的东西:

{{#if section1 || section2}}
.. content
{{/if}}
Run Code Online (Sandbox Code Playgroud)

我知道我可以写自己的帮手,但首先我要确保我不会重新发明轮子.

Nic*_*tto 504

这可以通过使用块助手"欺骗"来实现.这可能违背了开发Handlebars的人的意识形态.

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

然后,您可以像这样在模板中调用帮助程序

{{#ifCond v1 v2}}
    {{v1}} is equal to {{v2}}
{{else}}
    {{v1}} is not equal to {{v2}}
{{/ifCond}}
Run Code Online (Sandbox Code Playgroud)

  • 我不明白为什么开发人员喜欢让自己陷入困境. (104认同)
  • 这确实违背了Handlebars/Mustache的无逻辑性质,但是肯定是有用的,谢谢! (54认同)
  • 我不明白为什么AND/OR不能成为Handlebars的一部分.它不违背无逻辑的性质,因为已经有IF,UNLESS和EACH ......对于无逻辑的这么多 (32认同)
  • @BalaClark它真的没有逻辑吗?我的意思是它仍然有"如果"的陈述 - 仅仅因为它们被故意瘫痪并不会改变哲学. (28认同)
  • 请注意,这根本不适用于绑定属性(读取,Ember绑定).文字值很好,但不解析模型属性(使用Ember 1.0.0-rc.8和Handlebars 1.0.0测试),而`registerBoundHelper`不能处理Handlebars语法.解决方法是创建自定义视图:http://stackoverflow.com/questions/18005111/custom-handlebars-helper-parameter-is-not-resolved (6认同)
  • @StackOverflowed自己限制你的选择/障碍有助于遵循发展理念.有了一个可行的开发理念,当您尝试解决它旨在解决的问题时,实现它的API不应该让您感到不适.相反,它应该以一种奇怪的方式感受到权力:)(有点像禁欲).为了回到主题,要么Handlebars哲学是矛盾的,这个问题中描述的问题可以通过其后的解决方案来解决,把手API实现得很差或者这不是把手设计要解决的问题. (4认同)
  • 如果这是一种脚本语言,你必须定义自己的if条件逻辑,是不是喜欢去餐馆做自己的土豆? (2认同)
  • "我永远无法理解为什么开发人员喜欢阻碍了自己" - 我不明白为什么当有_plenty_替代品的人会选择的工具显然并不意味着这项工作. (2认同)

Jim*_*Jim 439

进一步采取解决方案.这会添加比较运算符.

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);
    }
});
Run Code Online (Sandbox Code Playgroud)

在这样的模板中使用它:

{{#ifCond var1 '==' var2}}
Run Code Online (Sandbox Code Playgroud)

咖啡脚本版

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
Run Code Online (Sandbox Code Playgroud)

  • 不要忘记''||'`和''&&'`.我添加了这些案例,它们非常有用. (20认同)
  • 作为车把的一个菜鸟,有一点不清楚的是你必须将操作符作为字符串传递,否则编译器会在标记模板时出错.{{#ifCond true'=='false}} (20认同)
  • 但如果v1和v2也是一个条件那我该如何使用呢?例如:if(value =="a"|| value =="b") (4认同)
  • 如果有这个,你可以做其他事吗? (3认同)
  • 我发现不评估对象属性的值.添加以下内容有助于`v1 = Ember.Handlebars.get(this,v1,options)``v2 = Ember.Handlebars.get(this,v2,options)` (2认同)

kev*_*ned 148

Handlebars支持嵌套操作.如果我们以稍微不同的方式编写逻辑,这会提供很多灵活性(以及更清晰的代码).

{{#if (or section1 section2)}}
.. content
{{/if}}
Run Code Online (Sandbox Code Playgroud)

实际上,我们可以添加各种逻辑:

{{#if (or 
        (eq section1 "foo")
        (ne section2 "bar"))}}
.. content
{{/if}}
Run Code Online (Sandbox Code Playgroud)

只需注册这些助手:

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);
    }
});
Run Code Online (Sandbox Code Playgroud)

  • 我们似乎已将Lisp构建到Handlebars中. (18认同)
  • 你的`和`和`或'助手只能使用2个参数,这不是你想要的.我设法重做了`和`和`或'助手,以支持两个以上的参数.将这个单行用于`和`:`return Array.prototype.slice.call(arguments,0,arguments.length - 1).every(Boolean);`并使用这个单行代码来表示`或`:`return Array.prototype.slice.call(arguments,0,arguments.length - 1).some(Boolean);`. (8认同)
  • 请注意,直到Ember 1.10中的HTMLBars才能实现这一点.此外,如果您愿意,那些帮助者将作为Ember CLI插件使用:https://github.com/jmurphyau/ember-truth-helpers. (5认同)
  • 一个[更高级的版本](https://gist.github.com/servel333/21e1eedbd70db5a7cfff327526c72bc5),可以在每个运算符上获取多个参数. (3认同)

ben*_*ael 86

对于那些生活在边缘的人来说,把这个提升一个档次.

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

把手助手: {{#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>
Run Code Online (Sandbox Code Playgroud)

产量

<p>
  BOOM
</p>
Run Code Online (Sandbox Code Playgroud)

JavaScript :( 这取决于另一个助手 - 继续阅读)

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

把手助手: {{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>
Run Code Online (Sandbox Code Playgroud)

输出:

<p>Url: hi Sam, http://example.com <---- this is your href, your Age is: 20</p>
Run Code Online (Sandbox Code Playgroud)

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));
Run Code Online (Sandbox Code Playgroud)
h1 {
  font-size: large;
}
.content {
  padding: 10px;
}
.person {
  padding: 5px;
  margin: 5px;
  border: 1px solid grey;
}
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

Moar

如果你想访问上层范围,这个稍微不同,表达式是所有参数的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}}
Run Code Online (Sandbox Code Playgroud)

使用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);
});
Run Code Online (Sandbox Code Playgroud)

  • 这很棒.把手不能告诉你怎么做:) (15认同)

jQw*_*rdy 30

有一种简单的方法可以在不编写辅助函数的情况下完成此操作......它可以在模板中完成.

{{#if cond1}}   
  {{#if con2}}   
    <div> and condition completed</div>  
  {{/if}}
{{else}}   
  <div> both conditions weren't true</div>  
{{/if}}
Run Code Online (Sandbox Code Playgroud)

编辑:反过来你可以这样做:

{{#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}}
Run Code Online (Sandbox Code Playgroud)

编辑/注意:从车把的网站:handlebarsjs.com这里是虚假值:

您可以使用if帮助器有条件地渲染块.如果它的参数返回false,undefined,null,""或[]("falsy"值),那么任何'cond'(如cond1或cond2)都不会被计为true.

  • 不是真的,你不比较两个值,你只是确保它们都存在,它是不同的. (9认同)
  • 实际上它以与javascript相同的方式对它进行评估,来自网站:"你可以使用if帮助器有条件地渲染一个块.如果它的参数返回false,undefined,null,""或[]("falsy"值),把手不会渲染块." (3认同)
  • 这不能正常工作.如果cond1为true且con2为false,则不会打印任何内容. (3认同)

dev*_*ett 19

这里发布的所有答案的一个问题是它们不能使用绑定属性,即当涉及的属性发生更改时,不会重新评估if条件.这是支持绑定的助手的稍微高级版本.它使用来自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;
  });
});
Run Code Online (Sandbox Code Playgroud)

你可以像这样使用它:

{{#ifeq obj.some.property "something"}}
  They are equal!
{{/ifeq}}
Run Code Online (Sandbox Code Playgroud)

  • 有没有人使用HTMLBars/Ember 1.10?Ember.Handlebars.bind似乎不再存在. (2认同)

Vin*_*ent 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);
    }
});
Run Code Online (Sandbox Code Playgroud)

  • 由于提到了有关脚本注入的警告,我强烈建议不要使用此帮助程序。在大型代码库中,这很容易导致严重的安全问题 (2认同)

Cle*_*uck 7

这是我使用的块助手的链接: 比较块助手.它支持所有标准运算符,并允许您编写如下所示的代码.这真的很方便.

{{#compare Database.Tables.Count ">" 5}}
There are more than 5 tables
{{/compare}}
Run Code Online (Sandbox Code Playgroud)

  • @augurone这不是本地帮手。如果您点击链接,您将看到它是一个自定义的帮助器。 (2认同)

Sat*_*lli 7

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

/* 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);
  });
Run Code Online (Sandbox Code Playgroud)

用法:

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

{{#checkIf list.length '>' 0 '&&' public '==' true}} <p>condition satisfied</p>{{/checkIf}}
Run Code Online (Sandbox Code Playgroud)


Emb*_*eak 5

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

ember 安装 ember-truth-helpers

您可以开始使用大多数逻辑运算符(eq、not-eq、not、and、or、gt、gte、lt、lte、xor)。

{{#if (or section1 section2)}}  
...content  
{{/if}}
Run Code Online (Sandbox Code Playgroud)

您甚至可以包含子表达式以进一步,

{{#if (or (eq section1 "section1") (eq section2 "section2") ) }}  
...content  
{{/if}}
Run Code Online (Sandbox Code Playgroud)


Mor*_*ich 5

三元助手的另一个歪曲解决方案:

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

<span>{{?: fooExists 'found it' 'nope, sorry'}}</span>
Run Code Online (Sandbox Code Playgroud)

或者一个简单的合并助手:

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

<span>{{?? foo bar}}</span>
Run Code Online (Sandbox Code Playgroud)

由于这些字符在车把标记中没有特殊含义,因此您可以随意将它们用作助手名称。