port5432
port5432

Reputation: 6371

Calling external functions from Meteor Template helpers

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

Answers (1)

Matt K
Matt K

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

Related Questions