Spacebars rendering according to index - meteor

I need to open a row when the index modulus is 0 and close it when it is 1, something similar to this idea:
{{each posts}}
{{#if #index%2==0}}
<div class="row">
{{/if}}
<div class="col-lg-6">HELLO</div>
{{#if #index%2==1}}
</div>
{{/if}}
{{/each}}
OF course that this code/idea doesn't compile. How can I achieve it?
UPDATE Sorry, maybe I didn't explain it well. What I want to do is something similar to this PHP code but using meteor. (changed some numbers for a better understanding).
for($i = 0; $i<count(array); $i++):
if($i%4 == 0):
echo '<div class="row">';
endif;
echo '<div class="col-lg-3">HELLO</div>';
if($i%4==3 || $i == count(array) -1):
echo '</div>';
endif;
endfor;
I have one solution with a helper that returns a two dimensional array there is another way of doing it.

you can get the index and then pass it to a helper to do your logic.
{{#each posts}}
{{#if isEven #index}}
<div class="row">
{{/if}}
<div class="col-lg-6">HELLO</div>
{{#if isOdd #index}}
</div>
{{/if}}
{{/each}}
Template.foo.helpers({
isEven(index) {
return (index % 2 == 0);
},
isOdd(index) {
return (index % 2 == 1);
}
});
edit:
btw, your if logic looks wrong for matching up the divs. i think you mean something more like this:
{{#each posts}}
{{#if isEven #index}}
<div class="row">
{{else}}
<div class="col-lg-6">HELLO
{{/if}}
</div>
{{/each}}
edit 2:
if Blaze is getting confused by how the divs are formatted, maybe de-confuse it like this. it's easier to read, too:
{{#each posts}}
{{#if isEven #index}}
<div class="row">
</div>
{{else}}
<div class="col-lg-6">HELLO
</div>
{{/if}}
{{/each}}

If you wish to create the element in the middle no matter what, I would do something like this
{{#each posts}}
<div class="{{#if isEven #index}}row{{/if}}">
<div class="col-lg-6">HELLO</div>
</div>
{{/each}}
where (similar to #zim suggestion) isEven would be a template helper taking the index as its argument
Template.hello.helpers({
isEven(index) {
return index % 2 === 0;
}
});

Related

I lose data context when i generate template with parameters

when I generate subtemplate in #each helper and i add parameter, then i lose data context, what is normally visible.
I found workaround by passing data fields to template by
{{> productItem parameter="test" name=name details=details}}
, but for more complicated collections that would be very tiresome... isn't there better option to solve that problem ?
<template name="main">
{{#each products}}
{{> productItem parameter="test"}}
{{/each}}
</template>
<template name="productItem">
<div class="product">
<p>{{name}}</p>
<p>{{details}}</p>
<p>{{parameter}}</p>
</div>
</template>
And javascript :
Template.main.helpers({
products: function(){
return Products.find({});
}
});
you are creating a new context ( it doesn't magically merge everything ), but its easy enough to include the original context.
you go :-
{{> productItem product=this parameter="test"}}
then
<template name="productItem">
<div class="product">
<p>{{product.name}}</p>
<p>{{product.details}}</p>
<p>{{parameter}}</p>
</div>
</template>
or
<template name="productItem">
<div class="product">
{{#with product}}
<p>{{name}}</p>
<p>{{details}}</p>
{{/with}}
<p>{{parameter}}</p>
</div>
</template>

How to do recursive templates in Meteor?

rather a theoretical question - how can I render recursive templates in Meteor? For example, displaying a comment on comment with unlimited number of comment sub-levels so that HTML would be diplayed as the following?
<section>
some text
<section>
nested text
<section>
further nested text and sections
.....
</section>
</section>
</section>
In my case I pass to the "tree" template a mongoDB document and this document can have unlimited number of sub-content levels. My example below doesn't work the way I want.
<template name="tree">
<div class="wrapper" style="border:1px solid red">
<ul>
{{#each getStructure}}
<li>
{{#each content}}
<ul>
<li>
<a class="item">{{text}}</a>
<!-- TODO: this stuff needs to be recursive.
{{#if sub_content}}
<ul>
{{#each sub_content}}
<li>
<a class="item">{{text}}</a>
{{#if sub_content}}
....
{{/if}}
</li>
{{/each}}
</ul>
{{/if}}
</li>
</ul>
{{/each}}
</li>
{{/each}}
</ul>
</div>
</template>
A simplified example of recirsuve, say you had a post sample template of:
<template name="post">
{{post_text}}
{{#each comments}}
{{>comment}}
{{/each}}
</template>
and a post helper of:
Template.post.helpers({
comments: function() {
return CommentCollection.find({post_id: this._id, parent_id: {$exists: 0}});
}
});
I would create a template for the comment layout and provide a helper in that for sub-comments, depending on your data structure something like the following:
<template name="comment">
{{comment_text}}
{{#each sub_comment}}
{{> comment}}
{{/each}}
</template>
and then the helper along the lines of:
Template.comment.helpers({
sub_comments: function() {
return CommentCollection.find({parent_id: this._id});
}
});
This would recursively produce the comments template for each sub-comment then roll back up the tree to the next #each and then print that comment and all of its sub-comments etc.

Polymorphism in Meteor Templates

Say I have a Meteor application which displays widgets. A widget can have one of several forms:
<template name="textWidget">
<h1>{{myTitle}}</h1>
<p>{{myTextContent}}</p>
</template>
<template name="imgWidget">
<h1>{{myTitle}}</h1>
<img src="{{myImagePath}}" />
</template>
<template name="listWidget">
<h1>{{myTitle}}</h1>
<ul>
{{#each items}}
{{> listWidgetItem}}
{{/each}}
</ul>
</template>
Is there a good pattern for rendering a specific template given a record type?
Naively, I can do something like:
<template name="masterTemplate">
{{#each widgets}}
{{#if widgetType "text"}}
{{> textWidget}}
{{else}}
{{#if widgetType "img"}}
{{> imgWidget}}
{{else}}
{{if ... }} ... {{/if}}
{{/if}}
{{#/if}}
{{/each}}
</template>
With a helper like:
Template.masterTemplate.widgetType = function(cmp) {
return cmp === this.data.type;
};
This seems like a very clunky and unflexible way to operate though. Am I missing an obvious library or design pattern for this use case?
You can try something like this:
UI.registerHelper('widget', function () {
var templateName = this.data.type + 'Widget';
return Template[templateName].extend({ data: this });
});
and you can use it as follows:
{{> widget context}}
or
{{#with context}}
{{> widget}}
{{/with}}

How can i add a hr element of each 3 of my looping array..using Handlebarsjs?

I have a array of elements, i am appending them all to my form element. all works fine. But i am not able to add a "hr" element to each of my 3rd label.. i tried this.
<script id="locale-template" type="text/x-handlebars-template">
{{#each this}}
{{#if #index % 3 === 0 }}
<hr/>
{{/if}}
<label><input type="checkbox" /> {{name}} </label>
{{/each}}
</script>
But not works.. can any one suggest me the correct way please..?
Thanks in advance
First register helper like showHr
Handlebars.registerHelper("showHr", function(index_count,block) {
if(parseInt(index_count)%3=== 0){
return block.fn(this);}
});
Now In Template
{{#showHr #index}}
<hr/>
{{/showHr}}
Or if you want you can write generic helper refer http://doginthehat.com.au/2012/02/comparison-block-helper-for-handlebars-templates/
Edit for comment question
Handlebars.registerHelper("moduloIf", function(index_count,mod,block) {
if(parseInt(index_count)%(mod)=== 0){
return block.fn(this);}
});
Considering index start from 0
// If index is 0 open div
// if index is 3 means open a div
{{#moduloIf #index 0}}
<div>
{{/moduloIf}}
{{#moduloIf #index 3}}
<div>
{{/moduloIf}}
{{name}}
// if index+1 is modulo 3 close div
{{#moduloIf #index+1 3}}
</div>
{{/moduloIf}}

Getting the outer context of a Meteor Template

I have the following use-case: There are rooms which have beds inside. (Bummer...)
There is a loop of rooms which uses a template "room".
<template name="rooms">
{{#each availableRooms}}
{{> room}}
{{/each}}
</template>
This template gets for each iteration a room. This is accessible by this.
<template name="room">
<div class="room-outer">
<button type="button" class="btn" data-toggle="collapse" data-target="#list-{{_id}}">
{{name}} : {{getBeds this}} beds free.
</button>
<div id="list-{{_id}}" class="collapse in room-inner">
{{#each guests_id}}
<div class="bed">
<div class="blanket">
{{showUser this}}
</div>
</div>
{{/each}}
</div>
</div>
</template>
Now I like to calculate some special value which I do by extending the template. I need now to pass the this variable to the getBeds function. Is it possible to do this by grabing outside the template and get the room into the function?
Template.room.getBeds = function (room) {
if (room.guests_id)
return room.beds - _.size(room.guests_id);
else
return room.beds;
};
Basically I don't want to have to write {{getBeds this}} but only {{getBeds}}
Shouldn't this work?
Template.room.getBeds = function () {
if (this.guests_id)
return this.beds - _.size(this.guests_id);
else
return this.beds;
};
See the docs:
Helpers can take arguments, and they receive the current template data in this:

Resources