Reputation: 225
Beginner question here: I'm working through the Discover Meteor book, Chapter 3 on Templates. This line of the template gives me pause:
<h3><a href="{{url}}">{{title}}</a><span>{{domain}}</span></h3>
What's going on here is the {{domain}}
expression is coming from the postItem
template helper and the {{url}}
and {{title}}
expressions are coming from the postsList
template helper. However, by just looking at the template, there is no way to tell which expression is handled by which template helper. I understand you can make the template more explicit by using the this
keyword in the template. However, instead of doing this, is there a way I can explicitly create a helper in the postItem
template? For example, I tried doing this, but it did not work:
Template.postItem.helpers({
title: this.title,
url: this.url,
domain: function() {
var a = document.createElement('a');
a.href = this.url;
return a.hostname;
}
});
And I don't understand why this would not work. I understand this may make the code more verbose, but personally, I would prefer the code to be more explicit than leaving it ambiguous.
Thanks for your help!
Upvotes: 0
Views: 77
Reputation: 1236
This is my preferred way to be explicit about data context using Blaze in Meteor.
You can see a working example here :
http://meteorpad.com/pad/rkybNCiKBpzEdcfHc/Template%20Parameters
I provide each child template an explicit list of parameters like this :
{{> player name=this.name score=this.score}}
In this example, each list item will only need to display a user's name and their score. So, the child template gets only two variables as its data context, name and score, and nothing else.
This helps me debug issues and define exactly which fields a template needs.
// Parent Template
Template.leaderboard.helpers({
players: function () {
return Players.find({}, { sort: { score: -1, name: 1 } });
}
});
<template name="leaderboard">
{{#each players}}
{{> player name=this.name score=this.score}}
{{/each}}
</template>
// Child Template
<template name="player">
<div>{{userName}} : {{userScore}}</div>
</template>
Template.player.helpers({
userName: function() {
return this.name;
},
userScore: function(){
return this.score;
}
});
Inside the template it can also be a good idea to throw errors if the data context fields are not available or the wrong type.
When I started with Meteor I had the very same question and it seemed awkward to me to have this idea of implied data context.
Upvotes: 1
Reputation: 20256
Your description of what's going on is a bit off. Let me attempt to clarify what's going on.
The two templates are:
<template name="postsList">
<div class="posts">
{{#each posts}}
{{> postItem}}
{{/each}}
</div>
</template>
<template name="postItem">
<div class="post">
<div class="post-content">
<h3><a href="{{url}}">{{title}}</a><span>{{domain}}</span></h3>
</div>
</div>
</template>
postList
template includes an iterator {{#each posts}}
posts
helper of the postItem
templatefind()
on a collection. Alternatively this helper could return an array of objects.postItem
template is included.this
{{title}}
{{this.title}}
Sometimes the object doesn't have all the data you need to display. You might need to reformat existing fields, combine them someway, convert them (ex: UTC to local time, $ to £ etc...), or lookup related data from a different collection. In those cases you need a helper to return the extra piece of data.
Directly manipulating the DOM in a helper in the way you're showing is unadvisable. Since helpers can be called repeatedly even with the same data context you would likely end up with many more a
elements than you expected.
In practice the distinction between a field value from the current data context and a helper value doesn't really matter to the presentation layer. It's not something that gets in your way of developing in Meteor. The common thing that crops up is that you insert a {{mything}}
in the markup but forget to define a helper for it and then it shows up as blank. Or you believe that your object has a key that it doesn't have and you also get a blank.
Upvotes: 1