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?
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">×</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
Try this:
In your template:
<option value={{key}} selected={{isSelected currentUser.property key}}>
Then have your helper return a boolean.
More on the topic here: https://github.com/meteor/meteor/wiki/Using-Blaze#conditional-attributes-with-no-value-eg-checked-selected
Although spacebars does not support equality, this method works to check for equality
you can use something like this
{{#if chkeq variable value}}
example
{{#if chkeq applicationStatus "Draft"}}
at least it worked for me
where chkeq is a global helper,
which goes something like this
chkeq:function(a,b){
if(a==b){
return true;}
else return false;
}
Related
I was using custom Handlebars helper extending the functionality of 'if' block.
In Ember 1.10 this doesnt work anymore as there is no Ember.Handlebars.bind property which allowed binding to the property....
Ember.Handlebars.registerHelper('ifCond', function (a, b, options) {
return Ember.Handlebars.bind.call(options, contexts[0], a, options, true, function(result) {
return result === b
});
});
The usage would be:
{{#ifCond property "value"}}
{{some-other-component}}
{{else}}
something other...
{{/ifCond}}
but this returns an error "Cannot read property 'call' of undefined"
Is there any way that I can bind to passed properties in helper? I cannot use registerBoundHelper because it doesn't support having child blocks...
I wanted to use Component instead of helper but then I cannot use the {{else}} block...
This solution for the helper was previously taken from Logical operator in a handlebars.js {{#if}} conditional
I actually managed to find a way to do it, so I'll write the answer for my own question...
Instead of using undocumented hacks, I used the proposed change: https://github.com/emberjs/ember.js/issues/10295
So my helper looks like this now:
Ember.Handlebars.registerBoundHelper('isSame', function(value1, value2) {
return value1 === value2
});
and the usage:
{{#if (isSame property "value")}}
{{some-other-component}}
{{else if (isSame property "otherValue"}}
something other...
{{else}}
something other...
{{/if}}
How can I can concatenate strings( or how to add classes ) on templates on EmberJs?
ex.
<script type="text/x-handlebars">
// This div I want to add a class go, Is this the right way to do it?
<div class="fly {{isGo}}">Fly now</div>
// Or it's something like this?
<div class="fly "{{isGo}} >Fly now</div>
</script>
bind-attr used to be a good way of working around a limitation within Ember's rendering. Now with HTMLbars Ember has recommend that we move away from bind-attr as we have more powerful methods.
Ember 1.13 deprecated bind-attr in favor of the new syntax.
http://emberjs.com/deprecations/v1.x/#toc_bind-attr
Working example of the two proposed methods can be seen in action on ember twiddle ,here:
https://ember-twiddle.com/38f69f01d2fd994af3b0965f10882005?openFiles=templates.application.hbs%2C
Method 1
If you want to do the combination inside your handlebars template you could do something like:
<div class={{concat "fly " isGo}}>Fly now</div>
Method 2
otherwise use a computed property like:
flyingClass: Ember.computed('isGo', function() {
// return a string with 'fly' and the value of
// isGo. Will be updated if isGo changes.
// Array values are created with space delimited by
// ['className', 'anotherClassName', 'lastClastName'].join(' ');
// => "className anotherClassName lastClassName"
let going = this.get('isGo') ? 'going' : ''
return ['fly', going].join(' ');
})
and then in your handlebars template:
<div class={{flyingClass}}>Fly now</div>
The main difference between the two methods depends on how you want your separation of concerns. Right now it might be easier to just do Method 1, but as conditions get more complicated you could hide more of the work in the computed property.
There is a complete discussion of this in the Ember guide: http://emberjs.com/guides/templates/binding-element-class-names/
But you'd do it like this:
<div {{bind-attr class="isGo"}}>Fly now</div>
And in your controller:
App.MyController = Ember.ObjectController.extend({
flightIsAGo: true,
isGo: function() {
return "fly"+this.get('flightIsAGo') ? ' isGo' : '';
}.property('flightIsAGo')
}
I'm create handlebars helper:
export default Ember.Handlebars.registerHelper('if-eq', function(v1, v2, options) {
if (this.get(v1) === this.get(v2)) {
return options.fn(this);
}
return options.inverse(this);
});
And execute like this:
{{#each item in model.cons }}
{{#if-eq model.currentUser.id item.record_poster_id}}
<div class="td author current">{{model.currentUser.name}}</div>
{{else}}
<div class="td author remote">{{model.remoteUser.name}}</div>
{{/if-eq}}
{{/each}}
I recieved variables like text "model.currentUser.id", using this.get(v1) I can get value.
But this.get working only for model.currentUser.id and don't work for item.record_poster_id (maybe because it's variable from the loop)
QUESION: how i can pass variable by value?
ANSWER: How to compare values in each?
You are passing the variable's value, you're just accessing them incorrectly. Why are you using this.get(v1) to access the argument? Just use v1. It's already the value you passed in, you don't have to do anything special to it.
Also, I'm not sure if that Handlebars syntax will work. Ember might require you to do something like this.
I want to disable an inputfield if a property is false or does not exist. To do this, you should need a reverse binding for the input helper, something like (pseudo code):
{{ input ... disabled=!isNew}}
After reading the docs, I could find nothing about reverse boolean structure.
Should I solve this by using a computed property*, or is there a better way?
*
Something like:
loginFieldDisabled: function() {
return ! this.get('isNew');
}.property('isNew')
For those who came to question by googling, currently you could use the Ember Truth helpers to achieve a solution for this problem:
{{input ... disabled=(not isNew)}}
I can think of two ways that I would do it. First, use a conditional block:
{{#if isNew}}
{{input}}
{{else}}
{{input disabled}}
{{/if}}
But that comes with its own set of issues, since it adds and removes the text field from the DOM. The other way would be to modify Ember.TextField. Here's something that would work (tested in a JSBin):
Ember.TextField.reopen({
notDisabled: function(key, value) {
if (arguments.length > 1) {
this.set('disabled', !value);
}
return !this.get('disabled');
}.property('disabled')
});
Then, in your template:
{{input notDisabled=isNew}}
The second one is probably what you want. You could also extend Ember.TextField instead of modifying it.
I have a Handlebars helper that takes a number and returns a class name. I want to run the helper only if foobar exists because it might not exist. My initial attempt was:
{{#each content}}
<div class="other_class {{#if foobar}}{{my_helper foobar}}{{/if}}"></div>
{{/each}}
This doesn't work because metamorph inserts script tag placeholders where the if helper is. My second attempt was:
{{#each content}}
<div class="other_class {{my_helper foobar}}"></div>
{{/each}}
This also doesn't work because when foobar does not exist, the string "foobar" is passed to my_helper.
I know that doing {{unbound foobar}} will render the value without binding it and thus without script tag placeholders. Is there a way to use if in an unbound way?
You could create a computed property and add it to classNameBindings of a view, see http://jsfiddle.net/pangratz666/MvpUZ/:
App.MyView = Ember.View.extend({
classNameBindings: 'omg'.w(),
omg: function(){
var foobar = Ember.getPath(this, 'content.foobar');
return (foobar && foobar === 42) ? 'my-class-name' : null;
}.property('content.foobar')
});
There is a helper for this. It's called unboundIf: see documentation
You can use it like this:
{{#unboundIf "content.shouldDisplayTitle"}}
{{content.title}}
{{/unboundIf}}
The expression is only evaluated once.