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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 07:48:16  来源:igfitidea点击:

Logical operator in a handlebars.js {{#if}} conditional

javascripthandlebars.js

提问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 语句的助手

  1. EXPRESSION is a properly escaped String
  2. Yes you NEEDto properly escape the string literals or just alternate single and double quotes
  3. you can access any global function or property i.e. encodeURIComponent(property)
  4. this example assumes you passed this context to your handlebars template( {name: 'Sam', age: '20' } ), notice ageis a string, just for so I can demo parseInt()later in this post
  1. EXPRESSION 是一个正确转义的字符串
  2. 是的,您需要正确转义字符串文字或仅交替使用单引号和双引号
  3. 您可以访问任何全局函数或属性,即 encodeURIComponent(property)
  4. 这个例子假设你把这个上下文传递给你的把手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表达式的助手

  1. EXPRESSION is a properly escaped String
  2. Yes you NEEDto properly escape the string literals or just alternate single and double quotes
  3. you can access any global function or property i.e. parseInt(property)
  4. this example assumes you passed this context to your handlebars template( {name: 'Sam', age: '20' } ), ageis a stringfor demo purpose, it can be anything..
  1. EXPRESSION 是一个正确转义的字符串
  2. 是的,您需要正确转义字符串文字或仅交替使用单引号和双引号
  3. 您可以访问任何全局函数或属性,即 parseInt(property)
  4. 这个例子假设你将此上下文传递给你的把手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 #ifhelper.

此处发布的所有答案的一个问题是它们不适用于绑定属性,即当所涉及的属性发生更改时不会重新评估 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 #ifhelper 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”。