Where am I going wrong with this reactive helper?

Hi there!

I’m trying to make a reactive global helper but I’m getting an error. The error reads Exception in queued task: TypeError: Cannot read property 'splice' of null.

I adapted an existing helper by following an example on the homepage of the Blaze documentation (first example.) I also referenced the UI.registerHelper section but I still seem to be doing something wrong.

var currentTime = new Blaze.Var(0);
UI.registerHelper('humanizedTime', function(timeOfEvent) {
  var diff = moment(timeOfEvent).diff(currentTime.get(), 'minutes');
  var hours = diff / 60;
  var days = hours / 24;
  var weeks = days / 7;

  if (weeks <= -2) {
    return moment(timeOfEvent).format('dddd, MMMM D, h:mm A');
  } else if (days <= -1) {
    return moment.duration(days, "days").humanize(true);
  } else if (hours <= -1) {
    return moment.duration(hours, "hours").humanize(true);
  } else {
    return moment.duration(diff, "minutes").humanize(true);
  }
});

setInterval(function () {
  currentTime.set(new Date());
}, 1000);

(And please feel free to make any and all proposals for improving this function.)

var currentTime = new Blaze.Var(new Date());

Exception from Tracker recompute function: Error: No such function: humanizedTime

Any idea?

You’re not trying to evaluate humaziedTime(<someTime>) in your JavaScript code, right? humanizedTime can only be used in Spacebars.

That’s correct. It only appears in one template as <h4>{{humanizedTime etoeventSubmitted}}</h4> and the declaration.

edit: I really should have included the whole error. The following is said to be coming from debug.js:41. WebStorm is highlighting .Var() as being Unresolved type Var.

I’m also running Meteor on Windows.

Exception from Tracker recompute function: Error: No such function: humanizedTime
    at Blaze.View.lookup (http://localhost:3000/packages/blaze.js?b0fa84e3d7a352d325a81441bf2b6dd19cb7e554:2889:15)
    at Spacebars.call (http://localhost:3000/packages/spacebars.js?7bafbe05ec09b6bbb6a3b276537e4995ab298a2f:172:18)
    at Spacebars.mustacheImpl (http://localhost:3000/packages/spacebars.js?7bafbe05ec09b6bbb6a3b276537e4995ab298a2f:109:25)
    at Object.Spacebars.mustache (http://localhost:3000/packages/spacebars.js?7bafbe05ec09b6bbb6a3b276537e4995ab298a2f:113:39)
    at null._render (http://localhost:3000/client/etoevents/template.etoeventItem.js?ba66cbb537e13d4c98119fc51d3805ebcd7386ba:52:22)
    at doRender (http://localhost:3000/packages/blaze.js?b0fa84e3d7a352d325a81441bf2b6dd19cb7e554:1928:25)
    at http://localhost:3000/packages/blaze.js?b0fa84e3d7a352d325a81441bf2b6dd19cb7e554:1821:18
    at Function.Template._withTemplateInstanceFunc (http://localhost:3000/packages/blaze.js?b0fa84e3d7a352d325a81441bf2b6dd19cb7e554:3383:12)
    at http://localhost:3000/packages/blaze.js?b0fa84e3d7a352d325a81441bf2b6dd19cb7e554:1820:29
    at Object.Blaze._withCurrentView (http://localhost:3000/packages/blaze.js?b0fa84e3d7a352d325a81441bf2b6dd19cb7e554:2105:12)

If I read this code right, you haven’t registered any (global) helper named humanizedTime. Are you sure the call to UI.registerHelper is executed before the helper is used?

Are you using the Meteor platform or the Blaze standalone project?

I need a badge that says, “I don’t know what I’m doing.”

I didn’t realize Blaze had a standalone project. But those are the docs I linked to in my original post so I guess I’m referencing the wrong docs? :blush:

Also, I thought [Template|UI].registerHelper was registering the helper globally, no?

I don’t know if this is executed before or after it’s being used. I was letting Meteor handle that. Part of the reason for this is because I don’t have a problem with this helper when it’s used normally (without the reactivity.) Normally it looks like this:

Template.registerHelper('humanizedTime', function(timeOfEvent) {
  var diff = moment(timeOfEvent).diff(new Date(), 'minutes');
  var hours = diff / 60;
  var days = hours / 24;
  var weeks = days / 7;

  if (weeks <= -2) {
    return moment(timeOfEvent).format('dddd, MMMM D, h:mm A');
  } else if (days <= -1) {
    return moment.duration(days, "days").humanize(true);
  } else if (hours <= -1) {
    return moment.duration(hours, "hours").humanize(true);
  } else {
    return moment.duration(diff, "minutes").humanize(true);
  }
});

Yea, if you use the Meteor platform, you should read the docs at http://docs.meteor.com/#/full/ instead, and you should use Template.registerHelper instead of UI.registerHelper.

It is not correct. Just look at lookup.js from blaze package

Blaze._globalHelpers = {};

// Documented as Template.registerHelper.
// This definition also provides back-compat for `UI.registerHelper`.
Blaze.registerHelper = function (name, func) {
  Blaze._globalHelpers[name] = func;
};

UI.registerHelper and Template.registerHelper are both Blaze.registerHelper
I guess that error could be the meteor-win-only issue

My point was that one should use Template.registerHelper in favor of UI.registerHelper on the Meteor platform.

I doubt this is a Windows related problem. The helper is registered on the client in the browser, which should be OS independent, but I don’t know.

@Giraffeslacks, can you share your code with us (GitHub?)?

I get the same result in both cases.

I appreciate your offer to help further but I’m afraid I can’t.

I’ll see if I can’t use another method to make this reactive and I’ll stick with using the standard docs as a reference.

I don’t see any Blaze.Var in the docs (Maybe you mean Blaze.ReactiveVar, even then, just use reactive-var package / ReactiveVar),

You could also cut out the middle-man and just use the tracker package. eg:

var timeDep = new Tracker.Dependency;
UI.registerHelper('humanizedTime', function(timeOfEvent) {
  timeDep.depend();
  var diff = moment(timeOfEvent).diff(new Date, 'minutes');
  var hours = diff / 60;
  var days = hours / 24;
  var weeks = days / 7;

  if (weeks <= -2) {
    return moment(timeOfEvent).format('dddd, MMMM D, h:mm A');
  } else if (days <= -1) {
    return moment.duration(days, "days").humanize(true);
  } else if (hours <= -1) {
    return moment.duration(hours, "hours").humanize(true);
  } else {
    return moment.duration(diff, "minutes").humanize(true);
  }
});

setInterval(function () {
  timeDep.changed();
}, 1000);
2 Likes

Hi @nathan_muir,

Thanks for your response. It worked! With a little help from http://docs.meteor.com/#/full/tracker.

I linked to the docs I was referencing in my original post: http://meteor.github.io/blaze/. Right on the homepage there it says var counter = new Blaze.Var(0);.

I had to make some changes to get it to work but that wasn’t too much trouble. The docs provided a straightforward example.

var currentTime = new Date();
var currentTimeDep = new Tracker.Dependency;
Template.registerHelper('humanizedTime', function(timeOfEvent) {
  currentTimeDep.depend();
  var diff = moment(timeOfEvent).diff(currentTime, 'minutes');
  var hours = diff / 60;
  var days = hours / 24;
  var weeks = days / 7;

  if (weeks <= -2) {
    return moment(timeOfEvent).format('dddd, MMMM D, h:mm A');
  } else if (days <= -1) {
    return moment.duration(days, "days").humanize(true);
  } else if (hours <= -1) {
    return moment.duration(hours, "hours").humanize(true);
  } else {
    return moment.duration(diff, "minutes").humanize(true);
  }
});
setInterval(function() {
  currentTime = new Date();
  currentTimeDep.changed();
}, 1000);

Great that the problem has been solved, but I’m really curious why the working solution works. On the Meteor Platform, Blaze.ReactiveVar is the same as ReactiveVar (if the reactive-var package has been added), and under the hood ReactiveVar uses Tracker.Dependency. I don’t see what difference it makes, anyone who knows?

@Peppe_LG The issue is that the original code uses Blaze.Var instead of Blaze.ReactiveVar.

I only suggested using a Tracker.Dependency instead of a var - however the solution by @Giraffeslacks somewhat defeats the point by storing a currentTime variable. (Which is effectively what a ReactiveVar would do).

eg. Is your abstraction “Invalidate this computation regularly” or, “time as a reactive data source”.

Thanks @nathan_muir, I missed he was using Blaze.Var ^^’ That explains everything, although @Giraffeslacks could have mention the undefined is not a function error he probably was getting :blush:

@Peppe_LG That’s kind of an unnecessary thing to say. I provided to the forum the code I was using and I provided the errors as well.

edit: I stand corrected. I did in fact miss the undefined is not a function error.

If you want a good example go there: