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

2020-01-22 11:56发布

Is there a way in handlebars JS to incorporate logical operators into the standard handlebars.js conditional operator? Something like this:

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

25条回答
趁早两清
2楼-- · 2020-01-22 12:25

Here we have vanilla handlebars for multiple logical && and || (and or):

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

Not so sure if it's "safe" to use "and" and "or"... maybe change to something like "op_and" and "op_or"?

查看更多
叼着烟拽天下
3楼-- · 2020-01-22 12:26

Unfortunately none of these solutions solve the problem of "OR" operator "cond1 || cond2".

  1. Check if first value is true
  2. Use "^" (or) and check if otherwise cond2 is true

    {{#if cond1}} DO THE ACTION {{^}} {{#if cond2}} DO THE ACTION {{/if}} {{/if}}

It breaks DRY rule. So why not use partial to make it less messy

{{#if cond1}}
    {{> subTemplate}}
{{^}}
    {{#if cond2}}
        {{> subTemplate}}
    {{/if}}
{{/if}}
查看更多
forever°为你锁心
4楼-- · 2020-01-22 12:29

I can understand why you would want to create a helper for situations where you have a large number of varied comparisons to perform within your template, but for a relatively small number of comparisons (or even one, which was what brought me to this page in the first place), it would probably just be easier to define a new handlebars variable in your view-rendering function call, like:

Pass to handlebars on render:

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

and then within your handlebars template:

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

I mention this for simplicity's sake, and also because it's an answer that may be quick and helpful while still complying with the logicless nature of Handlebars.

查看更多
Lonely孤独者°
5楼-- · 2020-01-22 12:29

Here's an approach I'm using for ember 1.10 and 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));
});

Then you can use it in your templates like this:

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

Where the arguments to the expression are passed in as p0,p1,p2 etc and p0 can also be referenced as this.

查看更多
萌系小妹纸
6楼-- · 2020-01-22 12:30

In Ember.js you can use inline if helper in if block helper. It can replace || logical operator, for example:

{{#if (if firstCondition firstCondition secondCondition)}}
  (firstCondition || (or) secondCondition) === true
{{/if}}
查看更多
贼婆χ
7楼-- · 2020-01-22 12:32

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 bind function from the Ember source, which is also used to implement the normal Ember #if helper.

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.

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}}
查看更多
登录 后发表回答