How to nest Handlebars JS? - meteor

I am getting a frustrating error because of my Handlebars JS templates.
Error: Parse error on line 9:
... {{/each}} {{/if}}
----------------------^
Expecting 'EOF'
Handlebars in question:
{{if showSingle}}
{{#with single}}
{{> postSingle}}
{{/with}}
{{else}}
{{#each posts}}
{{> postItem}}
{{/each}}
{{/if}}
Is nesting like this not possible?
Just to put things in context, this was working fine:
{{#each posts}}
{{> postItem}}
{{/each}}

Missing the # from the first if:
{{#if showSingle}}
{{#with single}}
{{> postSingle}}
{{/with}}
{{else}}
{{#each posts}}
{{> postItem}}
{{/each}}
{{/if}}

Related

Meteor show and hide Template on click

I want to show one template instead of another template on a button click. Similar to the "add comment" link in a StackOverFlow question. In the below example I want to replace {{> newCommentLink}} with {{> postEditor}}
<template name="main">
{{#each posts}}
{{> posts}}
{{/each}}
</template>
<template name="posts">
{{#each comments}}
{{> comment}}
{{/each}}
{{> newCommentLink}}
</template>
If this is not possible, is there any other way?
You can use a reactive variable to determine which template to show:
Template.posts.onCreated(function() {
this.newCommentLink = new ReactiveVar(true);
});
Template.posts.helpers({
shouldShowNewCommentLink() {
return Template.instance().newCommentLink.get();
}
});
Template.posts.events({
'click button': function(event, template) {
template.newCommentLink.set(!template.newCommentLink.get());
}
});
In template:
<template name="posts">
{{#each comments}}
{{> comment}}
{{/each}}
<button class="btn btn-default">Click me to switch...</button>
{{#if shouldShowNewCommentLink}}
{{> newCommentLink}}
{{else}}
{{>postEditor}}
{{/if}}
</template>

Fastest way to check whether the cursor returned by a template helper is empty?

I often do something like this, using the items helper twice:
{{#if items}}
<h1>Items</h1>
{{#each items}}
{{> item}}
{{/each}}
{{/if}}
Template.foo.helpers
items: ->
Items.find
bar: true
,
sort: created: -1
transform: (item) ->
i.good = true
i
Is Meteor doing extra work in this scenario? Would it be more efficient to switch the if to use something like areItems?
areItems: ->
Items.find
bar: true
.count() > 0
You can use {{else}}
{{#each this}}
{{> item}}
{{else}}
<h1>No Items</h1>
{{/each}}
In the template, you can use {{#with items}} and then either 'this.count' or 'this.length' to check whether your helper returned any items.
Use this.count if 'items' is a cursor, e.g. the result of a find() operation:
{{#with items}}
{{#if this.count}}
<h1>Items</h1>
{{#each this}}
{{> item}}
{{/each}}
{{/if}}
{{/with}}
Use this.length if 'items' is an array:
{{#with items}}
{{#if this.length}}
<h1>Items</h1>
{{#each this}}
{{> item}}
{{/each}}
{{/if}}
{{/with}}
Use #with, #if this.length, and .fetch:
{{#with items}}
{{#if this.length}}
<h1>Items</h1>
{{#each this}}
{{> item}}
{{/each}}
{{/if}}
{{/with}}
Template.foo.helpers
items: ->
Items.find
bar: true
,
sort: created: -1
transform: (item) ->
i.good = true
i
.fetch()
You can do what you want using spacebars' #with block tag.
Like this:
{{#with items}}
{{#if this.count}}<h1>Items</h1>{{/if}}
{{#each this}}
{{> item}}
{{/each}}
{{/with}}
The block tag is documented here. The relevant quote is:
If the argument to #with is falsy (by the same rules as for #if), the content is not rendered.
update: fixed code for desired behaviour. Also while my example demonstrates making one helper call it is better practice to make an 'itemList' template and include it by using {{> itemList items}}.
I found that simply {{#if items.count}} was sufficient.
{{#if items.count}}
<h2>Below there are items</h2>
{{/if}}
{{#each items}}
<div class="item-name">{{this.name}}</div>
{{else}}
<h2>There are no items</h2>
{{else}}

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}}

dynamically choose the right template to use

I am going through a list of posts and choose the right html handlebar template depending on the type of content( image, text, twitter post). This becomes rather ugly with more and more template types though:
<template name="postItem">
{{#if isType "image"}}
{{#if isSinglePost}}
{{>postImageSingle}}
{{else}}
{{>postImage}}
{{/if}}
{{/if}}
{{#if isType "rich"}}
{{#if isSinglePost}}
{{>postRichSingle}}
{{else}}
{{>postRich}}
{{/if}}
{{/if}}
{{#if isType "video"}}
{{#if isSinglePost}}
{{>postRichSingle}}
{{else}}
{{>postRich}}
{{/if}}
{{/if}}
{{#if isType "file"}}
{{#if isMimeType "audio/wav"}}
{{>postAudio}}
{{else}}
{{>postFile}}
{{/if}}
{{/if}}
{{#if isType "link"}}
{{#if isProviderName this "Twitter"}}
{{>postTwitter}}
{{else}}
{{#if isSinglePost }}
{{>postLinkSingle}}
{{else}}
{{>postLink}}
{{/if}}
{{/if}}
{{/if}}
{{#if isType "preview"}}
{{>postPreview}}
{{/if}}
{{#if isType "photo"}}
{{>postImage}}
{{/if}}
</template>
It would be better to move the logic into a helper function, but what I struggle with is how I could return the name of the template to use from the helper function.
{{>getTemplateName}}
Template.postItem.getTemplateName = function () {
return postImage;
};
but this of course gives me:
Exception from Deps recompute: Error: No such template 'getTemplateName'
The {{> template}} syntax is for inserting templates only, while for helpers you use {{helper}}, without the angle bracket >. Remove the bracket from your helper invocation, and render the needed subtemplate inside the helper:
Template.postItem.getTemplateName = function() {
return new Handlebars.safeString(Template.postImage());
};

Handlebars.js - {{#each data}} nested in {{#if data}}

I would like to be able to do below with Handlebars.js. Is this possible?
{{#if data}}
{{#each data}}
do something here
{{/each}}
{{/else}
No data, sorry!
{/if}
Of course, check here: http://jsfiddle.net/PXQUA/
And you have few typos in your template:
{{#if data}}
{{#each data}}
{{this}}
{{/each}}
{{else}}
No data, sorry!
{{/if}}

Resources