Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to wait on Meteor.users when changing profile field

I'm using the profile field in Meteor.users system defined collection to store information about the last message user read on every communication channel with the following structure:

profile : {
    lastMsgRead : [
        {channelId: 'YYEBNEI7894K', messageCreatedAt: '14578970667"}
        {channelId: 'GERYUE789774', messageCreatedAt: '14578999845"}
    ]
}

I discovered that reading lastMsgRead field fails because of on the client the array in still empty at the time of read. I correctly publish this field to the client through:

Meteor.publish(null, function() {
    return Meteor.users.find({}, {fields: {_id: 1, username: 1, emails: 1, profile :1}});

and I read its value from a client library located in the lib directory, in this way:

var chHistory = Meteor.user().profile.lastMsgRead;

Debugging my code it looks like the changes I make to the profile field have not been propagated to all the client at the time I read them. So I need to wait for the subscription Meteor.users gets ready, but I don't have its handle ─ you get this automatically from the framework.

How can I wait for the Meteor.users subscription gets ready?

like image 329
massimosgrelli Avatar asked May 17 '15 10:05

massimosgrelli


1 Answers

Because meteor doesn't provide you with a handle for the current user's subscription, there isn't an obvious way to wait on the data. Here are some options:

use a guard

The typical way to handle this problem is to add guards to your code. In your template(s) which are experiencing this issue you could write something like:

var user = Meteor.user();
var lastMsgRead = user && user.profile && user.profile.lastMsgRead;

If you find you write that code a lot, you could factor it out into a shared function:

var extractProfileValue = function(key) {
  var user = Meteor.user();
  return user && user.profile && user.profile[key];
};

And use it like this:

var lastMsgRead = extractProfileValue('lastMsgRead');

show a spinner

You can test for the existence of the user's profile in the template itself:

<template name='myTemplate'>
  {{#unless currentUser.profile}}
    // show spinner or loading template here
  {{else}}
    // rest of template here
  {{/unles}}
</template>

If you want this experience on all of your pages, you could add it to your layout template(s).

redundant publisher

WARNING: I have not tried this

One way to get a user's subscription handle is just to add a redundant publisher and subscribe to it:

Meteor.publish('myProfile', function() {
  return Meteor.users.find(this.userId, {fields: {profile: 1}});
});

Then in your router:

waitOn: function () {
  return Meteor.subscribe('myProfile');
}
like image 74
David Weldon Avatar answered Sep 19 '22 20:09

David Weldon