Reactively add or remove class - meteor

How can you reactively add or remove a class to an element with spacebars?
Also can anyone point me in the direction of the documentation for spacebars format.
Specifically logical functions in the {{#if condition1 && condition2}} style.
Thanks

Currently there are no logical operations allowed in "if" statements, but you can workaround this by providing a custom helper. The easiest way to reactively modify your class would be:
<div class="{{#if isActive}}active{{/if}}"></div>
or just
<div class="{{yieldClass}}"></div>
where yieldClass is some (possibly reactive) helper in your template.

Spacebars currently don't provide a way to perform logical (nor other) functions for arguments.
If you need to make logical operations on your if helper arguments in several places, it is best to define your own custom helper:
UI.registerHelper('and', function(a, b) {
return a && b;
});
{{#if and condition1 condition2}}
...
{{/if}

Related

Meteor Spacebars Helpers - Passing another spacebar as helper argument

I have been trying to pass the spacebar as another spacebar argument like this :
{{helperfunction {{argument}} }}
here the {{argument}} is also coming from another helper function.
Is there any way to achieve this?
You do not need to use the additional {{}}.
lets say that argument is a string and helper function is expecting a string then {{helperFn argument}} is like helperFn(argument). So the single {{ ... }} is sufficient. {{}} using the bracket is like opening a javascript context (kind of) so if arguments is already a defined var that is in scope, there is no need to add additional {{}}.
if you do want to compose blaze helper functions, you can do that by using parens like so {{helperFn1 (helperFn2 argument)}}.
this would be like helperFn1( helperFn2(argument) )
also, if argument is a function, I believe that blaze will call the function and return the result automatically. => {{helperFn argument}} is like helperFn(argument()).
hope that helps a bit.

Meteor/Blaze - Simple string concatenate in parameter

I know how to do this via the more expanded, and probably "proper" method, but I was wondering if there are any simpler ways to do this.
{{> alert message="My message"}}
Basically, I have a template that takes a value message. I want to give it the message Logged in as: samanime, where samanime is whatever the value of currentUser.username.
I know I can do this by creating a helper to concatenate the two parts for me, but is there some way that I can do it without an extra helper? Maybe something like:
{{> alert message="Logged in as: ${currentUser.username}"}}
After playing around with a couple ideas, I think I've come up with a reasonable solution that doesn't violate (too much) the separate of view and logic.
First, to do the actual concatenation, I made a concat helper:
// Takes any number of arguments and returns them concatenated.
UI.registerHelper('concat', function () {
return Array.prototype.slice.call(arguments, 0, -1).join('');
});
Example usage:
{{ concat "a" "b" "c" }}
{{! output: "abc" }}
Then, I made a new block helper, withResult:
Helper:
UI.registerHelper('withResult', function () {
Template._withResult.helpers({result: this.valueOf()});
return Template._withResult;
});
Template:
<template name="_withResult">
{{> UI.contentBlock result=result}}
</template>
Example usage:
{{#withResult concat "a" "b" "c"}}
{{> alert message=result}}
{{/withResult}}
Basically, it takes the result of whatever is the block call (in this case, concat) and puts it in the variable result available to the template.
I think this is a fairly clean and flexible way to not only concat, but also to get other simple multiple-parameter values across. The only negative at this point is it only allows you to create one variable (as each scope puts it in the same spot). However, that can be overcome by having other helpers return objects.
Of course, this is something that you don't want to abuse, as it would blur the clean line that we try to keep between view and logic.

How to give default alternatives in Handlebars

After going through the docs twice, I gave up and wrote this in a template:
{{#if myVar}}{{myVar}}{{else}}{{myDefaultVar}}{{/if}}
Am I missing some Handlebars built-in feature for this, as it feels like it is going to come up a lot! (I realize I can write my own helper for it, and will do that if Handlebars has nothing built-in.)
Pending some discovery that Handlebars supports this natively, here is the helper I wrote:
Handlebars.registerHelper("P", function(){
for(var i=0;i<arguments.length;++i)if(arguments[i])return arguments[i];
});
So the long {{#if}} becomes this:
{{P myVar myDefaultVar}}
It allows multiple defaults, using whichever comes first, so I might have something like this:
Welcome {{P user.nickname user.fullName "guest"}}!
If the user has given a nickname, use that, otherwise use their full name. If they have given neither, refer to them as "guest".

Does Ember have {{itemView}} helper that can be used with {{#collection}}?

Actually, I am looking for methods that let the View be responsible for marking the first or the last item in a collection view, and I found this one How do I add a separator between elements in an {{#each}} loop except after the last element?
.But I don't want to define itemViewClass template's attrs(classNames for example) in javascript, can I just use a {{itemView}} helper or something to define a itemView template?
{{#collection contentBinding="dataList" tagName="ol" classNames="list" itemViewClass="ItemView"}}
{{#itemView classNames="item" classNamesBinding="isLastItem:last"}}
item templates
{{/itemView}}
{{/collection}}
Although, this can be solved in another ways, I just want to know if I can find a built-in support. And I do search for a long time, just can't find Ember.Handlebars.collection's document, it's not in the latest API doc.
starting with the master version of Emberjs, you may try using a custom Handlebars "bound" helper.
it would look something like this :
{{#each item in collection}}
{{#isLastElement item}}
template if last
{{else}}
template if not
{{/isLastElement}}
both templates
{{/each}}
Ember.Handlebars.registerBoundHelper('islastElement',
function(item, options) {
if(functionTellingIfThisIsLastElement(item))
return options.fn(this);
else
return options.inverse(this);
}
);
This is just another way to see things, with functionTellingIfThisIsLastElement either looking in the collection or a property in your item. To access the collection you would have to change some stuffs here, to get the good context + parameters, depending on your code.

Loop modulo condition with Handlebars.js

I am looping through objects using Handlebars. My issue is that there is no way I can easily add some code every x iterations (% 2 or % 3).
I tried the solution proposed on How can I create conditional row classes using Handlebars.js?. It doesn't work because I am using the framework called Meteor, and my "collection" is coming from a MongoDB query through Meteor. Using that solution, the "Context" is equal to the whole Meteor context and my collection is nowhere to be found...
My first idea was to create a new boolean property on my object called "eof" and a Handlebars condition would be triggered with some more code if it is equal to true... but I would like something cleaner and not dependent of the server-side.
How would you do it?
Thanks a lot!
See Tom Coleman's answer.
You could add a template helper that would look something like:
Template.tableWithDifferentColorRows.helpers({
modulo3: function() {
return (this.index % 3) === 0;
},
});
// in the html:
{{#each_with_index collection}}
<div {{#if modulo3}}style='color:purple'{{/if}}>
actual content...
</div>
{{/each}}

Resources