42

I've tried to understand this post regarding this concept, however, I'm failing to get it. I have the following simple setup:

/server/test.js
Meteor.methods({ 
  abc: function() {
    var result = {};
    result.foo = "Hello ";
    result.bar = "World!";
    return result;
  }
});

/client/myapp.js
var q = Meteor.call('abc');
console.log(q);

This structure returns to the console undefined.

If I change the myapp.js file to:

Meteor.call('abc', function(err, data) {
  !err ? console.log(data) : console.log(err);
}

I receive the Object in my console.

Ideally this is what I'd like to be able to do, but it doesn't work, stating in the console: Cannot read property 'greeting' of undefined

/client/myapp.js
var q = Meteor.call('abc');

Template.hello.greeting = function() {
   return q.foo;
}

Any help in passing the data from the server object into the template would be greatly appreciated. I'm still learning JavaScript & Meteor.

Thanks!

Community
  • 1
  • 1
rs77
  • 7,637
  • 2
  • 17
  • 17

4 Answers4

78

From the Meteor.call documentation:

On the client, if you do not pass a callback and you are not inside a stub, call will return undefined, and you will have no way to get the return value of the method. That is because the client doesn't have fibers, so there is not actually any way it can block on the remote execution of a method.

So, you'll want to do it like this:

Meteor.call('abc', function(err, data) {
  if (err)
    console.log(err);

  Session.set('q', data);
});

Template.hello.greeting = function() {
  return Session.get('q').foo;
};

This will reactively update the template once the data is available.

Tamara Wijsman
  • 11,892
  • 8
  • 51
  • 80
  • 1
    Hi Tom, thanks so much for your quick response! I had to close your Meteor.call function with `);` and append a semi-colon at the end of the `Template.hello.greeting` function to get it to finally work (if you wanted to edit your code). Thanks again for your help! – rs77 May 20 '12 at 23:53
  • 1
    Hi Tom, quick question - if the data isn't expected to change at all long term, is there a way to do without having to use the session object? Seems very wasteful and verbose otherwise, as the number of variables increases. Thank you. – Stephan Tual Apr 30 '13 at 08:28
  • You could perhaps try Amplify to access localStorage. – Tamara Wijsman Apr 30 '13 at 11:40
  • 1
    For a meteor beginner it seems odd that for templates, which by nature are dynamic, one should have to shuffle data via sessions... Is this truly the best way to do this? – kontur Jan 27 '15 at 18:55
  • @kontur: It might be possible to redefine the Template.hello.greeting function. In comparison, the session allows reuse. – Tamara Wijsman Jan 28 '15 at 11:30
  • You can also use `ReactiveVar` instead of the `Session`, either way this still isn't reactive since it relies on calling `Meteor.call`. I'm searching for a way to get a server var from a Meteor method reactively to the client. – evolross Oct 13 '15 at 02:41
  • This is not correct. Session does not appear on the server side. – Thai Tran Nov 11 '15 at 06:04
  • @ThaiTran: It is correct, the abc function is on the server side. – Tamara Wijsman Nov 11 '15 at 10:08
  • 2
    Is this answer no longer true? I am calling my method with a callback and it always returns a result `undefined`. It's not erroring out either, I checked that already. – Merlin -they-them- Nov 29 '15 at 14:47
  • @kontur the Meteor way to do this is not Method calls, it's subscriptions. Methods are closer to "remote procedure calls". – T3db0t Apr 11 '16 at 20:43
1

This happens because Npm.require has Async behavior. That's the reason that you have to write a callback for Meteor.call.

But there is a solution, just use install(mrt add npm) and you'll get a function named Meteor.sync(//...) with this you can do both games: sync and async in your Meteor.call().

Reference: http://www.sitepoint.com/create-a-meteor-app-using-npm-module/

icc97
  • 8,746
  • 6
  • 60
  • 75
0

You can get the return value of a Meteor method for use in a template by using a reactive variable. Check out the working demonstration on Meteorpad

  • The example in Meteorpad doesn't work for me. Also, deploying the example works... sort of. That is, it works once, but, for me, the method isn't called when the underlying information is updated. – MastaBaba Jan 21 '16 at 00:24
  • 1
    Methods are not themselves reactive, but can be called from within a reactive context such as Template.instance().autorun() or template helpers. – Brylie Christopher Oxley Jan 21 '16 at 02:46
0

I went for a ghetto solution. But, it works for me, which is what matters, to me. Below is my code, which, in concept, I think, solves OP's problem.

In the client's main.js:

Meteor.setInterval(function() {
    confirmLogin();

}, 5000); 

This runs the confirmLogin() function every five seconds.

The confirmLogin function (in the client's main.js):

function confirmLogin() {
    Meteor.call('loggedIn', function (error, result) {
        Session.set("loggedIn", result);
    });

}

The loggedIn method (in the server's main.js):

loggedIn: function () {
    var toReturn = false;
    var userDetails = Meteor.user();
    if (typeof userDetails["services"] !== "undefined") {
        if (typeof userDetails["services"]["facebook"] != "undefined") {
            toReturn = true;
        }
    }

    return toReturn;
},

The relevant helper:

loggedIn: function () {
    return Session.get("loggedIn");
}
MastaBaba
  • 955
  • 1
  • 8
  • 27