Check for equality in Spacebars?

SylvainB picture SylvainB · Jul 9, 2014 · Viewed 11.5k times · Source

I am trying to do what I think should be a very simple task, but have been failing to do so in the past hour. I want to select a select option by default if the user property matches the value.

<select name="myName">
  {{#each addKeys myTable}} <!-- addKeys creates variables for keys and values -->
    <option value="{{key}}" {{#if currentUser.property === key}}selected="selected"{{/if}}>{{value}}</option>
  {{/each}}
</select>

Now I thought this was straightforward enough to be implemented. But it turns out that Spacebars do not allow conditional operators other than the negation exclamation mark, so equal signs are out of question. I then tried something horrible for the sake of trying:

In template myTemplate:

<select name="myName">
  {{#each addKeys myTable}}
    <option value="{{key}}" {{isSelected currentUser.property key}}>{{value}}</option>
  {{/each}}
</select>

In mytemplate.js :

Template.myTemplate.helpers({
  isSelected: function(v1, v2) {
    if (v1 === v2)
      return "selected=\"selected\"";
    return '';
  }
});

Not only is this code terrible, terrible to look at, it does not work:

Exception in Meteor UI: String contains an invalid character

I don't understand why something that simple seems so impossible to achieve. Am I missing something there?

Answer

KyleMit picture KyleMit · Feb 25, 2015

Here's an overview of {{#if}} statements in Spacebars

Property

Of course the simplest possible implementation is when the scoped object has a property that evaluates to a boolean

For example if you had:

var item = {
  text: 'hello',
  checked: false
};

Then you could evaluate an if block like this:

class="{{#if checked}}checked{{/if}}"

Function

We could also evaluate a function here as well. Rather than add a function to the item, we can add a function to the helper and it will inherit the datacontext of the item being passed to it. So if we had the following helper:

Template.item.helpers({
    saysHi: function() {
      return this.text === "hi";
    }
});

Then we could run the following code:

<template name="item">
   {{text}}
   {{#if saysHi}} - Hi Back {{/if}}
</template>

Note: The helper's implementation can access the current data context as this.

Function with Parameters

You can also pass any number of parameters to helper functions like this:

Template: {{frob a b c verily=true}}
Helper Call: frob(a, b, c, Spacebars.kw({verily: true}))

When applied to our if block, we can do the following:

{{#if equals owner currentUser._id}}
    <button class="delete">&times;</button>
{{/if}}

Then add equals to our template helper like this:

Template.item.helpers({
    equals: function(v1, v2) {
        return (v1 === v2);
    }
});

Universal Helpers

Since this is a generic method that could be useful anywhere, we should add it to every template instead of recreating it.

Note: To create a helper that can be used in any template, use Template.registerHelper.

Template.registerHelper('equals',
    function(v1, v2) {
        return (v1 === v2);
    }
);

Here's a working Demo in MeteorPad that includes one of each of the types of IF's constructed here