How to access another collection by ID in Meteor template? - javascript

Let's say I have a Posts collection, the data for which looks like this:
var post1 = {
title: "First post",
post: "Post content",
comments: [<comment id>, <another comment id>, <etc>]
};
And I have a corresponding Comments collection. I've published and subscribed to both collections and want to display a post with it's comments.
How do I go about displaying the comments for that specific post?
<template name="post">
<h1>{{title}}</h1>
<p>{{post}}</p>
{{#each comments}}
// Only have access to the ID
{{/each}}
</template>
I could create a helper like this:
Template.post.helpers({
displayComment: function(id) {
return Comments.findOne(id).fetch().comment;
}
});
and do:
<template name="post">
<h1>{{title}}</h1>
<p>{{post}}</p>
{{#each comments}}
{{displayComment #index}}
{{/each}}
</template>
But then I'd have to create a helper for each of the comment object's properties, etc.
What's the clean way to do it? I don't want to populate the comments field on the post object, since that would mean calling .fetch(), and posts would no longer be reactive.

A couple of suggestions:
<template name="post">
<h1>{{title}}</h1>
<p>{{post}}</p>
{{#each comments}}
{{#with commentDetails}}
{{userName}} //
{{content}} // These are properties of a comment document
{{upvotes}} //
{{/with}}
{{/each}}
</template>
Template.post.helpers({
commentDetails: function() {
return Comments.findOne(this);
}
});
That will set the data context within each with block to be the comment object returned by looking up the current _id (which is the value of this in the commentDetails helper within the each block).
An alternative would be to just use an each block on its own, but have it iterate over a cursor:
<template name="post">
<h1>{{title}}</h1>
<p>{{post}}</p>
{{#each commentCursor}}
{{content}}
... // other properties
{{/each}}
</template>
Template.post.helpers({
commentCursor: function() {
return Comments.find({_id: {$in: this.comments}});
}
});

Related

Meteor: Using variable in child template

I'm using template-level subscriptions, but I have some problems to use the results in a child template:
As I'm loading the template example, the template exampleChild will be displayed (just take this as an basic example - I know this doesn't make sense right now).
On creating the main template, the subscription is done and the data gets stored in a helper:
Template
<template name="example">
{{> Template.dynamic template=switch}}
</template>
<template name="exampleChild">
<h1>{{result}}</h1>
</template>
Helper
Template.example.helpers({
switch: function() { return 'exampleChild'; },
result: function() { return Template.instance().result(); },
});
Event
Template.example.onCreated(function() {
var instance = this;
instance.autorun(function () {
var subscription = instance.subscribe('posts');
});
instance.result = function() {
return Collection.findOne({ _id: Session.get('id') });
}
});
If I would put the {{result}} in the example-Template, everything is working. But I need to use the variable in the child template.
Did you try:
<template name="example">
{{#with result}}
{{> Template.dynamic template=switch}}
{{/with}}
</template>
<template name="exampleChild">
<h1>{{this}}</h1>
</template>
With doc
When doing that, I prefer wrap the data context result into an object, to have something proper on the child like:
Template.example.helpers({
switch: function() { return 'exampleChild'; },
data: function() { return {result: Template.instance().result()} },
});
<template name="example">
{{#with data}}
{{> Template.dynamic template=switch}}
{{/with}}
</template>
<template name="exampleChild">
<h1>{{result}}</h1>
</template>
Hope it's help
You could store the result in a session variable, and then add another helper to exampleChild that waits for the session variable.

Why does nested each in template output nothing

While this is rendered as expected:
{{#each Items}} // a collection
{{title}}
{{/each}}
{{#each types}} // another ollection
{{refId}}
{{/each}}
if I put it together:
{{#each Items}}
{{title}}
{{#each types}}
{{refId}}
{{/each}}
{{/each}}
The #each types is empty.
The template helpers:
Template.menuItems.helpers({
restMenuItems: function() {
return RestMenuItems.find({restRefId: this._id}, {sort:Template.instance().sort.get()});
},
restMenuSideItems: function() {
return RestMenuSideItems.find({restRefId: this._id}, {sort:Template.instance().sort.get()});
}
});
Template.menuItems.onCreated( function(){
this.subscribe('restMenuItems');
this.subscribe('restMenuSideItems');
});
And some of the template code:
{{#each restMenuItems}}
<div>
<select class="list-group select_side_addons">
{{#each restMenuSideItems}}
<option>{{restRefId}}</option>
{{/each}}
</select>
</div>
{{/each}}
Even when replacing {{#each restMenuSideItems}} by {{#each ../restMenuSideItems}}, nothing appears.
What's wrong?
Because the #each clause changes the data context to the current item.
If you want a list of types inside each of the Items, you can get the parent data context using ...
If types is an attribute of the parent context:
{{#each Items}}
{{title}}
{{#each ../types}}
{{refId}}
{{/each}}
{{/each}}
If types is a template helper, you can pass the parent context as an argument to it:
{{#each Items}}
{{title}}
{{#each types ..}}
{{refId}}
{{/each}}
{{/each}}
and use the context for your query.
Template.myTemplate.helpers({
types: function(parent) {
// you now have the parent context here.
// use parent._id etc. where you used this._id in the
// "flat" version.
}
});

meteor template: parse html content

I saved some HTML-content in my collection. By using IronRouter data() will be used to set the cursor/array. In this example I just show an example array.
Now the HTML-content isn't shown correctly, as it doesn't get parsed. The user would see the HTML-tags. What do I have to do to get the content displayed correctly?
IronRouter
Router.route('/article/:_id', {
name: 'article',
data: function () {
var articles = [{ title: 'title', content: '<strong>content</strong>'}];
return { articles: articles };
}
});
template
<template name="article">
{{#each articles}}
<h1>{{title}}</h1>
<section>{{content}}</section>
{{/each}}
</template>
Use Handlebars triple-stash:
<template name="article">
{{#each articles}}
<h1>{{title}}</h1>
<section>{{{description}}}</section>
{{/each}}
</template>

Ember use separate child template files

I have the below template file (actually used for my component)
{{#each details.secs as |sec|}}
<div class="row">
{{#each secs.flds as |fld|}}
// if fld.id is 'abc', use abc.hbs
// if fld.id is 'xyz', use xyz.hbs
{{/each}}
</div>
{{/each}}
My question is how can I use separate sub-template files and include them in the above parent file (based on condition)
Thus if field.id is 'abc', it should use rendering logic from abc.hbs
Also abc.hbs would need the 'field' model input for rendering purpose (It's output should get appended to the main template)
With Ember 2.0, creating and registering our own eq (equals) helper is super easy:
ember generate helper eq
Include our equality function:
// app/helpers/eq.js
import Ember from 'ember';
export function eq(params, hash) {
return (params[0] === params[1]);
}
export default Ember.Helper.helper(eq);
And use it!
{{#each details.sections as |section|}}
<div class="row">
{{#each section.fields as |field|}}
{{#if (eq field.id "abc")}}
{{abc-component data=field}}
{{/if}}
 {{#if eq field.id "xyz)}}
{{xyz-component data=field}}
{{/if}}
{{/each}}
</div>
{{/each}}

How render a route relevant subheader with meteor blaze?

The end result of all of what I am about to go over is the subheader is not rendering on screen like i want it to.
Currently there is a mongo collection subheader with a category field and a texth field.
Subheader = new Mongo.Collection('subheader');
Meteor.methods({
subheaderInsert: function(subheaderIdAttributes) {
check(String);
check(subheaderIdAttributes, {
texth: String,
category: String
});
var subheaderId = _.extend(postAttributes, {
submitted: new Date()
});
var subheaderId = SubheaderId.insert(subheader);
return {
_id: subheaderId
};
}
});
There is a route that subscribes to the subheader and other page data.
Router.route('/', {
name: 'home',
controller: MissionstatementpostController,
waitOn:function () {
return Meteor.subscribe('subheader', 'home');
}
});
The publish function appears to work fine.
Meteor.publish('subheader', function(cat) {
return Subheader.find({category: cat});
});
The correct doc from the mongodb collection is reaching the client. this can be seen by
Subheader.findOne(); output Object {_id: "NPo5cwqgjYY6i9rtx", texth: "ex text", category: "home"}
The problem starts here
The template loaded by the Controller in this case MissionstatementpostController is postlist
<template name="postsList">
<div class="posts page">
{{> subheader}}
<div class="wrapper">
{{#each posts}}
{{> postItem}}
{{/each}}
</div>
{{#if nextPath}}
<a class="load-more" href="{{nextPath}}">Load more</a>
{{else}}
{{#unless ready}}
{{> spinner}}
{{/unless}}
{{/if}}
</div>
</template>
Here is the subheader template
<template name="subheader">
<div class="container">
<p>{{{texth}}}</p>
</div>
</template>
So what did I mess-up?
thanks
you must create a template helper for your subheader template. To return just the texth field, the helper will be like this.
Template.subheader.helpers({
texth: function() {
var sh = Subheader.findOne();
return sh && sh.texth;
}
});
You can return the whole document and use the #with helper inside the template.
Template.subheader.helpers({
subh: function() {
return Subheader.findOne();
}
});
<template name="subheader">
{{#with subh}}
<div class="container">
<p>{{{texth}}}</p>
</div>
{{/with}}
</template>
You can find more info about template helpers on Meteor Docs.

Categories