I'm running the latest Meteor (v1.1.0.3) on OS X 10.6.8 in Firefox 39.0.
I'm using accounts-ui
and accounts-google
for login management. I have a hand-rolled profile form with (among other things) a 'name' field. The initial value of this field should be either the name that is already set in their profile or the one that Google supplies.
I've defined the following template helper:
Template.profile_edit.helpers({
my_name: (function () {var u=Meteor.user(); return u.profile.name || u.services.google.name;}())
});
I use the value in my template as {{ my_name }}
. When I start meteor everything compiles just fine, but when I load the profile page I get the following Javascript error:
TypeError: u is undefined
...me: (function () {var u=Meteor.user(); return u.profile.name || u.services.googl...
Not immediately relevant, but just for completeness:
Why is this error happening and how can I solve it?
The Problem
This is a common issue that people have when first starting out with Meteor. The problem is that when this helper is executed during page load, depending on the response time for the publication from the server, the data for the currently logged in user may not be available yet. This makes it seem intermittent because at times the data is published in time, and others it's not.
Possible Solutions
One possible solution is to install meteorhacks:fast-render
. This will publish the logged in user (due to the null publication) with the initial html for the page and guarantee that the user is available when this helper is run. Data other than the currently logged in user will need to be properly set up as subscriptions on the router for fast render to take effect.
The other solution, and one that will work without installation of a new package is to guard against undefined. This will effectively let the helper return undefined when there is no data, but once the data is available the helper will reactively rerun and the proper data will be returned.
Template.profile_edit.helpers({
my_name: function () {
var u=Meteor.user();
if(u){
return u.profile.name || u.services.google.name;
}
}
});
Aside
In your helper I notice that you are using syntax like my_name:(function(){}())
. While this will give you what seems like a desired outcome, the problem is that you are immediately invoking this function and assigning its value to the my_name
helper instead of assigning it a function that can be called multiple times when the value changes. This breaks reactivity and so the second solution would not work due to it's reliance on it.
Template.profile_edit.helpers({
my_name: (function () {
/*
This is immediately invoked and basically
like using my_name: "bob"
*/
}())
});