How can I write an if not x statement in an HBS template file?
At present, I use an if/else clause in order to achieve that:
{{#if x}}
{{else}}
Some Text
{{/if}}
Is there a way to simplify this and use a single if statement?
I've tried stuff like {{#if !x}} and {{#if ^x}}, but it didn't work of course.
Looking on the web for HBS logical operators, I couldn't quite find the syntax for a logical-not.
Update
I should emphasize that in my case x is undefined.
I've learned it "the hard way", while trying:
{{#if not x}}
Some Text
{{/if}}
Which threw TypeError: Cannot read property 'includeZero' of undefined.
Have you tried unless?
<div class="entry">
{{#unless license}}
<h3 class="warning">WARNING: This entry does not have a license!</h3>
{{/unless}}
</div>
You can use the unless helper as the inverse of the if helper. Its
block will be rendered if the expression returns a falsy value.
https://handlebarsjs.com/builtin_helpers.html
You can also considers custom helpers:
Handlebars.registerHelper("ifNot", function(a, options){
if (!a) {
return options.fn(this);
}else{
try{
return options.inverse(this);
}catch(e){
//no else statement
}
}
});
Related
I have the following json object -
{
"type": "typeOne",
"Children": [
{
"ChildType": "ChildTypeOne",
"Settings": {
"IsChildTypeOne": true
}
},
{
"ChildType": "ChildTypeTwo",
"Settings": {
"IsChildTypeTwo": true
}
}
]
}
My handlebars template contains the following snippet -
{{#each Children}}
{{#if Settings.IsChildTypeOne}}
ChildTypeOne!!
{{else}}
ChildTypeTwo!!
{{/if}}
{{/each}}
If I run this data through the template, the only thing that ever renders is ChildTypeTwo!!. So it seems that the if statement isn't properly evaluating IsChildTypeOne. The strange part is that if I put a statement in to display the value of IsChildTypeOne in the else clause, the value is displayed as true for the first ChildType.
Does anyone have any thoughts as to why this is not working as expected?
NOTE - the json posted above is a trimmed down version of my actual object. The real object has nested Children arrays that reuse the same object structure. So for instance, in my example, ChildTypeOne can also have a Childrens array with other objects within it.
EDIT****
So in stepping through the code, I found that if I had my type defined as follows -
...
"Settings" : {
"IsChildTypeOne": 'true'
}
...
it appears to work. Removing the single quoted causes the value to be read as undefined when stepping through.
Given charrs answer didn't seem to help, and the fact that your JSON is more complex than what you've posted, maybe your actual template isn't referencing a parent context correctly? For instance, if you wanted to access the type field in #each children block, it would look like this:
{{#each Children}}
{{#if Settings.IsChildTypeOne}}
{{../type}}
{{/if}}
{{/each}}
This ended up being related to the process being used to serialize the json string into an object. Please see the issue here for an explanation.
Can you try changing the handlebar template code as below:
{{#Children}}
{{#if Settings.IsChildTypeOne}}
ChildTypeOne!!!
{{else}}
ChildTypeTwo!!!
{{/if}}
{{/Children}}
This would iterate your array of Children and would give you result as
ChildTypeOne!!!
ChildTypeTwo!!!
Since your json has two elements one which has ChildTypeOne true and other not.
Sample handelbar:
<div class="entry">
<h1>{{title}}</h1>
<div class="body">
{{body}}
{{#Children}}
{{#if Settings.IsChildTypeOne}}
ChildTypeOne!!!
{{else}}
ChildTypeTwo!!!
{{/if}}
{{/Children}}
</div>
</div>
The html Output for above template :
<div class="entry">
<h1>My New Post</h1>
<div class="body">
This is my first post!
ChildTypeOne!!!
ChildTypeTwo!!!
</div>
</div>
You can see ChildTypeOne!!! for first element is coming.
Looking at this Using Blaze guide, it seems Blaze supports {{#if}} and {{else}} statements, but I have't seen examples of an if-else statement. Is this supported in Blaze? Or do I have to do an additional if block inside the else block, which can get ugly.
I tried {{else if}}, but that gave an error.
{{#if en}}{{text.en}}{{else if tc}}{{text.tc}}{{/if}}
Spacebars uses the same control flow structure as handlebars so the answer is the same as this one. In your case:
{{#if en}}
{{text.en}}
{{else}}
{{#if tc}}
{{text.tc}}
{{/if}}
{{/if}}
Side note - one of the nice things about jade is that it supports else if.
Sometimes a better alternative is to move the logic into a helper like this:
Template.myTemplate.helpers({
textValue: function() {
if (this.en) {
return this.text.tc;
} else if (this.tc) {
return this.text.tc;
}
}
});
<template name="myTemplate">
<p>{{textValue}}</p>
</template>
The current version of Blaze supports else if - see below for a sample format and reference to the github issue resolution.
{{#if isUserProfile}}
<h3>User Profile</h3>
{{else if isLawyerProfile}}
<h3>Lawyer Profile</h3>
{{else}}
<h3>Test</h3>
{{/if}}
Reference Link: GitHub Else If Issue Resoltion
Following on from #David Wheldon's excellent answer, it's also worth noting that you can pass parameters to your JavaScript helper functions from your Blaze template.
So, for example the code below selectively renders the options for a select list by calling the helper method with the line isSelected region customerCompany:
{{#if isSelected region customerCompany}}
<option value={{region._id}} selected>{{region.name}}</option>
{{else}}
<option value={{region._id}}>{{region.name}}</option>
{{/if}}
and then in the js file:
isSelected: function (region, customer) {
return customer.salesRegionId === region._id;
},
This approach of passing in your variables to your helpers is generally recommended to avoid the confusion that can the arise with the changing meaning of the this keyword when using templates.
I've created a custom block helper for Meteor 0.9.3 using information from the following URL:
https://github.com/meteor/meteor/wiki/Using-Blaze#new-pattern-for-defining-custom-block-helpers
It can be used within a Spacebars template like so:
{{#ifEqual value1="stringOrNumber_1" value2="stringOrNumber_2"}}
<h1>The values ARE equal!</h1>
{{else}}
<h1>The values are NOT equal!</h1>
{{/ifEqual}}
Here is the code:
<template name="ifEqual">
{{#if isEqual value1 value2}}
{{> UI.contentBlock}}
{{else}}
{{> UI.elseBlock}}
{{/if}}
</template>
Template.ifEqual.isEqual = function (value1, value2) {
return value1 === value2;
};
My question is:
Is there a possible way to make this less clunky?
I would much prefer code that can be used within a template like so:
{{#ifEqual "stringOrNumber_1" "stringOrNumber_2"}}
...
I would register a global equals helper:
Template.registerHelper('equals', function(value1, value2){
return value1 === value2
})
And then use it like this:
{{#if equals "abc" "abc"}}
<p>They're equal :)</p>
{{else}}
<p>They're not equal :(</p>
{{/if}}
Though, you may be interested in using the underscore-helper package instead, so you don't have to define this (and similar) helpers yourself.
I have started using Handlebars.js. It seems that there is no built in conditionals like else if.
I want to have something like this
{{#if type.one }}
do something ... IF
{{else if type.two}}
do something ... ELSE IF
{{else}}
do something ... ELSE
{{/if}}
But this doesn't work. How do I do ELSE IF with handlebars? Is writing a custom helper is the only option ? If yes then please provide some pointers to write this helper.
You can't do this with a custom helper as Handlebars if-ish helpers only understand two parts: the "if" part and the "else" part. You can nest things though:
{{#if type.one}}
do something ... IF
{{else}}
{{#if type.two}}
do something ... ELSE IF
{{else}}
{{#if type.three}}
...
{{else}}
...
{{/if}}
{{/if}}
{{/if}}
That sort of thing will get nasty fast so you probably don't want to do that. A better approach would (as usual with Handlebars) be to push the logic into your JavaScript so that at most one of type.one, type.two, type.three, ... would be true; then you could:
{{#if type.one}}
...
{{/if}}
{{#if type.two}}
...
{{/if}}
{{#if type.three}}
...
{{/if}}
If you have a lot of options for type or if the bodies in your {{#if}}s are complicated, you could switch to partials. You'd have to add a custom helper to build a partial name based on a template variable though; something like this:
Handlebars.registerHelper('show_type', function(type) {
var types = ['one', 'two', 'three'];
var partial;
for(var i = 0; i < types.length; ++i) {
if(!type[types[i]])
continue;
partial = '_partial_' + types[i];
break;
}
if(partial)
return Handlebars.partials[name](this);
else
return '';
});
and then, assuming your partials are all registered and consistently named, you could say:
{{show_type type}}
Since Handlebars 3.0 the syntax described by OP does work out of the box! See: https://github.com/wycats/handlebars.js/pull/892 for more information.
Note:
For Ember, since version 1.10 and up this does work too. See also:
http://emberjs.com/blog/2015/02/07/ember-1-10-0-released.html#toc_chained-else-blocks
if you are using ember like framework,
{{#if isAtWork}}
Ship that code!
{{else if isReading}}
You can finish War and Peace eventually...
{{/if}}
link : http://guides.emberjs.com/v1.12.0/templates/conditionals/
You can do this:
{{#if type.one}}
...
{{else}} {{#if type.two}}
...
{{else}} {{#if type.three}}
...
{{else}}
...
{{/if}}{{/if}}{{/if}}
If you want a switch behaviour, you might be interested in Dan Harper's helpers, you will be able to do something like :
{{#is type 1}}
<p>Do something when 1.</p>
{{else}}{{#is type 2}}
<p>Do something when 2.</p>
{{else}}{{#is type 3}}
<p>Do something when 3.</p>
{{/is}}{{/is}}{{/is}}
Here is the jsfiddle.
The exact syntax that the OP has written will work in Ember Canary today with the
ember-htmlbars-inline-if-helper feature flag enabled.
I am trying to write a conditional if statement helper for Handlebars.js. Essentially, I want to put an "active" class on a link if it is the Apply Now page.
Helper:
Handlebars.registerHelper('isApplyNow', function(block) {
if(this.title == "Apply Now") {
return block(this);
} else {
return block.inverse(this);
}
});
And Template:
<ul>
{{#each pages}}
<li>
{{#isApplyNow}}
<a href="{{url}}" class ='active'>{{this.title}}</a>
{{else}}
{{this.title}}
{{/if}}
</li>
{{/each}}
</ul>
But, I am getting a very bare-bones javascript error:
Uncaught [object Object] in handlebars-1.0.0.beta.2.js:595
Can anyone see if I am writing this improperly?
Thanks!
Referenced articles:
Calling Helper Within If Block in Handlebars Template
http://thinkvitamin.com/code/handlebars-js-part-2-partials-and-helpers/
I do see one minor syntax mistake which I believe could be the issue. If you are going to use a helper that takes a block, then you have to close it with the helper name. See how I've replaced your {{/if}} with {{/isApplyNow}}, like so:
{{#isApplyNow}}
<a href="{{url}}" class ='active'>{{this.title}}</a>
{{else}}
{{this.title}}
{{/isApplyNow}}
NOTE:
block(this) in the helper will not work anymore. Instead, use block.fn(this)
e.g.
Handlebars.registerHelper('isApplyNow', function(block) {
if (this.title === "Apply Now")
return block.fn(this);
else
return block.inverse(this);
});