Reputation: 6371
I am trying to build a moderately reusable complex component in Meteor. It will be included in multiple templates with similar data structures and I am trying to achieve something like an Angular Directive.
The data context looks something like this:
var post = {
title: 'A test post',
author: 'Joe Bloggs',
bookmarked: true,
bookmarkCount: 25
}
In the HTML template I have something like this:
<template name="postDetail">
<div class="jumbotron">
<h3>{{title}}</h3>
{{> footerLinks}}
</div>
</template>
The footerLinks template is the reusable component I am trying to now build. I'd like have it as self-contained as possible, with it's own js logic. A simplified version is:
<template name="footerLinks">
{{author}} · {{formattedBookmarkCount}}
</template>
The {{author}} comes directly from the data context. I would like to use a function to build the text for the bookmark counts. Surprisingly this doesn't work, it doesn't even return the default.
Template.footerLinks.helpers({
updatedAt: 'wow',
formattedBookmarkCount: function () {
switch (bookmarkCount) {
case 0:
return "No bookmarks";
case 1:
return "1 bookmark";
default:
return bookmarkCount + " bookmarks";
}
}
});
But in any case I'd like to keep the actual helper simple and refer to external functions. For example:
Template.footerLinks.helpers({
updatedAt: 'wow',
formattedBookmarkCount: formatBookmarks(bookmarkCount)
});
.... somewhere else ....
function formatBookmarks(bookmarkCount) {
// call another function
return calcMessage(bookmarkCount);
}
function calcMessage(bookmarkCount) {
return bookmarkCount + " bookmarks";
}
To take it a step further, I'd like to access additional Meteor collections in the sub functions.
PARTIAL ANSWER
Thank you to @steph643 for pointing out the use of this. The following code now works:
Template.footerLinks.helpers({
updatedAt: 'wow',
formattedBookmarkCount: function() {
switch (this.bookmarkCount) {
case 0:
return "No bookmarks";
case 1:
return "1 bookmark";
default:
return this.bookmarkCount + " bookmarks";
}
},
But instead I would like to move this logic elsewhere, and possibly call it like this (which doesn't work):
Template.footerLinks.helpers({
updatedAt: 'wow',
formattedBookmarkCount: formatBookmarks()
}
Template.registerHelper('formatBookmarks', function() {
return this.bookmarkCount + " bookmarks";
}
This will return an error of
Uncaught ReferenceError: formatBookmarks is not defined
Upvotes: 0
Views: 219
Reputation: 4948
This is mostly a javascript thing. When you register a helper you're passing in an object that has a bunch of methods inside it & Meteor does its magic & puts those in a reactive context. If you want to use the function just inside helpers, then use a global helper like you kinda did, just rename the global to what you want & remove the local helper.
A second option is to create a global function & call it through the helper.
window.formatCount = function(count, singular, plural) {
switch (count) {
case 0:
return "No " + plural;
case 1:
return count + ' ' + singular;
default:
return count + ' ' + plural;
}
};
Template.registerHelper('formatBookmarksCount', function() {
return window.formatCount(this.bookmarkCount, 'bookmark', 'bookmarks')
}
Now you can use it anywhere on the client & you can consider namespacing a global object to avoid using window
if you want (plenty of posts on SO regarding this).
Upvotes: 1