1

I'm trying to access (another) user's details on the client side in meteor. I have a server side method called 'userDetails' that I'm calling from a template helper called 'acc'.

Server method:

'userDetails': function(userId) {
      check(userId, String);
      return Meteor.users.findOne({_id: userId},
                                  {fields: {
                                    "services.facebook.first_name": 1,
                                    "profile.birthday": 1,
                                    "services.facebook.gender": 1,
                                    "profile.location.name": 1
                                  }});
    }

Template helper:

acc: function(_id) {
    Meteor.call('userDetails', _id, function(err, res) {
      if(err) throw error;
      return res;
    });
  }

When I try to access acc.profile.birthday in the template I don't get anything. What could cause this?

L4zl0w
  • 1,069
  • 4
  • 15
  • 42
  • You cannot access a Template helper like that. You have to use `acc` in the Template itself to see the output. – Soubhik Mondal Apr 02 '16 at 19:07
  • Hi @BlazeSahlzen, are you saying I can't use {{acc.profile.birthday}} in the template? Because that's what I'm doing... – L4zl0w Apr 02 '16 at 19:09
  • 1
    Oh, I'm sorry, I misunderstood. Yes, you can do that. You could try consoling `res` object before returning it just to be sure of what structure the object has. – Soubhik Mondal Apr 02 '16 at 19:16

2 Answers2

2

You have to wrap the return in a else statement.

if(error) {

}
else {
   return res;
}

The call to you method in asynchronous. This means that the callback function will be executed when your server method completes.

If you want to display the result on a template, you have two possibilities:

1/ Use a session.

acc: function(_id) {
  Meteor.call('userDetails', _id, function(err, res) {
    if(err){
    }else{
      Session.set('data', res)
    }

  });
  return Session.get('data')
}

2/ Use Template subscriptions (better solution): On the server, you publish the data:

Meteor.publish("data", function(){
     return Meteor.users.findOne(...)
});

On the client, you subscribe:

Template.mytemplate.onCreated(function () {   
    Template.instance().subscribe("data");
});

Then directly on the client you will be able to create a helper and call the findOne.

In the html:

  {{#if Template.subscriptionsReady}}
    {{#each myHelper}}
       {{acc.profile.birthday}}
    {{/each}}
  {{else}}
    <p>Loading...</p>
  {{/if}}

Important Notice about users: Users profile are editable by default. Please read this: https://dweldon.silvrback.com/common-mistakes

hlx
  • 182
  • 1
  • 4
  • 15
  • Thanks @hlx, it's a nice and comprehensive answer, however I'm not sure that I would have a second helper to return the session. – L4zl0w Apr 02 '16 at 20:00
  • @L4zl0w I updated the answer so you won't need a second helper. Please mark the answer so the question does not appear a unanswered anymore – hlx Apr 02 '16 at 20:09
2

Meteor calls are asynchronous calls, that is why your helper is not returning any data.

Best option here is to either use Session or ReactiveVar or ReactiveDict

I'll use Session option here

acc: function(_id) {
  Meteor.call('userDetails', _id, function(err, res) {
    if(err){

    }else{
      Session.set('userDetails', res)
    }

  });
  return Session.get('userDetails')
}

In your html you can use this helper like this

{{#if acc}}
  {{name}}
  ...
{{else}}
  <p>Information not found</p>
{{/if}}
Sasikanth
  • 3,045
  • 1
  • 22
  • 45