How to do recursive templates in Meteor? - 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.

Related

when to reference a property that is not a valid identifier, how can I use segment-literal notation?

In the document handlebars
{{#each articles.[10].[#comments]}}
<h1>{{subject}}</h1>
<div>
{{body}}
</div>
{{/each}}
but I want such use it
{{#each nav-list.value}}
<li class="nav-{{#index}}">
{{{../[content.value].value}}}
</li>
{{/each}}
Obviously, it dons't work! How should I implement this...

Calling external template from a loop in meteor

From the Meteor templates tutorial here: (https://www.meteor.com/tutorials/blaze/templates)
We see that we can call a template {{> task}} inside the loop over tasks. However, when I try to get the task template in its own file - it no longer has access to the data. What is the correct way to do this?
<body>
<div class="container">
<header>
<h1>Todo List</h1>
</header>
<ul>
{{#each tasks}}
{{> task}}
{{/each}}
</ul>
</div>
</body>
<template name="task">
<li>{{text}}</li>
</template>
Figured it out. Basically, I was importing the task.html in the main.js, but not the accompanying task.js. So all the conditional helpers I had were not loaded and hence not working.
We need to pass value to the template which we are calling. And I assume tasks helper is implemented. Here I'm passing current value using 'this'.
<body>
<div class="container">
<header>
<h1>Todo List</h1>
</header>
<ul>
{{#each tasks}}
{{> task this}}
{{/each}}
</ul>
</div>
</body>
<template name="task">
<li>{{this}}</li>
</template>

Creating UI comment component with blaze

I'm trying to create a comments component with Blaze but i don't know how to handle the replies.
This is the schema for the 'comment' element:
_id, authorId, message, replies (those are comment ids), isReply (boolean).
Then I created a template with html
{{#each message}}
<div class="message">
<h2>{{author}}</h2>
<p>{{message</p>
<a class="button">Reply</a>
</div>
{{#each replies}}
<div class="message">
<h2>{{author}}</h2>
<p>{{message</p>
<a class="button">Reply</a>
</div>
{{/each}}
{{/each}}
Well, how do I handle the replies of the replies? Any Idea?
You need to use the templates recursively! An example
In your case, something like the following:
{{#each message}}
<div class="message">
<h2>{{author}}</h2>
<p>{{message</p>
<a class="button">Reply</a>
</div>
{{#each replies}}
{{> reply}}
{{/each}}
{{/each}}
<template name="reply">
<div class="message">
<h2>{{author}}</h2>
<p>{{message</p>
<a class="button">Reply</a>
{{#each replies}}
{{> reply}}
{{/each}}
</div>
</template>
You'll need a replies helper for the reply template that gets the replies to that reply.

Meteor accounts-list

I want to display all registered accounts in my meteor app. I published and subscibed to the Meteor.users collection and build a template to show email-addresses. The problem is I don't understand how I should navigate the data.
<template name="contacts">
<br>
<ul class="list-group">
{{#each users}}
<li class="list-group-item">
<span class="badge">14</span>
{{emails}}
</li>
{{/each}}
</ul>
</template>
{{emails}} is an array with json-objects and I don't know how to handle it to get the "address" field displayed.
This is my JS:
Template.kontakte.users = function (){
return Meteor.users.find();
}
First create a subtemplate, looks better:
<template name="contacts">
<ul class="list-group">
{{#each users}}
{{> user}}
{{/each}}
</ul>
</template>
<template name="user">
<li class="list-group-item">
<span class="badge">14</span>
{{email}}
</li>
</template>
In template user the userObject is available via this pointer. The email can be shown with helper functions.
Template.user.helpers({
email: function() {
return this.emails[0].address;
}
});
Note, this just shows the first email in your array.

How to filter the data from a collection loop?

Im trying to build a related info widget, based on the data from the YAML front-matter.
Each page on my collection has some tags associated, and the idea would be to only show those pages who have tags in common with the currently viewed page.
I've managed to get the complete tags outputting the existent pages with the following code:
<section class="see-also">
{{#each tags}}
<p>In <span class="tag">{{tag}}</span>:</p>
{{#each pages}}
<li>{{data.title}}</li>
{{/each}}
{{/each}}
</section>
Can I apply some sort of filter on {{#each tags}} ?
Thanks.
There's an inArray helper that you can use to test if the current tag is in the tags collection on the page being currently rendered:
<section class="see-also">
{{#each tags}}
{{#inArray ../page.tags tag }}
<p>In <span class="tag">{{tag}}</span>:</p>
{{#each pages}}
<li>{{data.title}}</li>
{{/each}}
{{/inArray}}
{{/each}}
</section>
You might have to modify the parent path syntax to account for the additional block helper:
<section class="see-also">
{{#each tags}}
{{#inArray ../page.tags tag }}
<p>In <span class="tag">{{tag}}</span>:</p>
{{#each ../pages}}
<li>{{../data.title}}</li>
{{/each}}
{{/inArray}}
{{/each}}
</section>

Resources