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

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

Related

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

Any way to pass an element from one context to another?

I have a meteor template that looks something like the following. Essentially I would like to pass something from my parent template to my child. Is there a way to do this?
<template name="parent">
Hello my name is {{name}}
{{#each children}}
{{> child}}
{{/each}}
</template>
<template name="child">
Hello my name is {{child_name}} and my parent's name is [not sure what to do]
</template>
Any help would be greatly appreciated!
Use the dotdot operator to traverse to parent views.
<template name="parent">
Hello my name is {{name}}
{{#each children}}
{{> child}}
{{/each}}
</template>
<template name="child">
Hello my name is {{child_name}} and my parent's name is {{../name}}
</template>
See demo here and documentation here

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());
};

How to nest Handlebars JS?

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

Resources