Correct example of getting sync data on client from a server method


#1

This is an answer, not a question.

Since it was a bit tricky to find a working example of getting data from a server method on a client in a sync way, I’ve decided to share some working solutions so that it might help someone else. In particular my task was to have a server method to perform search in Mongo, and then, once search is completed, show results in the client. The important thing here is the ‘once search is completed’, because I did not want to have any false responses from the method before it actually finishes it’s work.

If you have following method on server:

Meteor.methods({
  testServerMethod() {
    return 'hello world';
  },
});

and try to call the method from the client without callback, like this:

const test = Meteor.call('testServerMethod');
console.log('test', test);

you will get ‘test, undefined.’


Even if you experiment with adding a callback like this (leaving console.log outside of the callback is intentional)

const test = Meteor.call('testServerMethod', function(error, result){
  return result;
});
console.log('test', test);

you will still be getting 'test, undefined', as test can be printed already even though there is nothing assigned to it.


Now the only correct solution if you’d like to do it in a clean way (without any external modules) is to assign the callback result to a reactive variable. I would suggest using specifically created reactive variable for this instead of Session, and then do following (in my case the method was triggered after route url has been changed):

Meteor.Test_template.onCreated(function(){
  const test = new ReactiveVar();

  this.autorun(function(){
    FlowRouter.watchPathChange();
    Meteor.call('testServerMethod', function(error, result){
      if (result) test.set(result);
    });
    console.log('test', test.get());
  });
});

Now from this example every time you change your url, the server method will be triggered and once it finishes, the result will be passed to the reactive variable, to change of which the console.log listens to, and fires (prints) it once it is changed.


While looking through solutions I have tried the https://atmospherejs.com/simple/reactive-method but did not like it because it fired false undefined response the very first time it was triggered, while I wanted to avoid any multiple firings.

Another option is using Promises and async/await syntax, but it seemed too complex for my specific task, and eventually I was not sure if one can actually read a response from a Promise in Meteor without any external packages, can we?


#2

Just out of interest, why would you need to do this synchronously?


#3

Sorry, I did not get the question… Could you please clarify?


#4

Why would you ever need to use a meteor method synchronously on the client in the first place?

Instead of your example

const test = Meteor.call('testServerMethod', function(error, result){
  return result;
});
console.log('test', test);

Why not

 Meteor.call('testServerMethod', function(error, result){
   console.log('test', result);
   // Some other code
});


#5

Ah… My real situation is rather complex (depending if it is a searched or non-searched request, it gets data from a collection on the client or on the server, and that is managed by an external function), so while experimenting with different solutions I ended up with something like this that worked.

But now looking through the code I can see that indeed it can be optimised even more by putting additional callback to the function… so that I can avoid the reactive variable. Nevertheless the example may be helpful for someone.