How to make client wait for an async response from server call

Hey Everyone.

I have a Meteor.call method in my client that sends some info to the server side method, which then runs a python script to process. I can return data from the script to the server just fine, but then how do I get the client to wait until the server side method gets its values from the python script? Preferably want to have the client show a waiting animation of some kind until it gets a value that isn’t undefined from the server.

I have an example here: http://meteor-ssr-loadable.minhnguyen.me/test
the source code you can find it here: https://github.com/minhna/meteor-react-ssr/blob/master/imports/ui/components/test/syncMethodCall.js
It’s not perfect but it works.

I normally handle it with the UI state. For example, in react, I set the state variable isFetchingData to true before calling the Meteor method. Then in the UI, I display an animation when isFetchingData is true. When the method call returns, I set the state variable isFetchingData to false.

1 Like

The problem is if you don’t use something like async/await, the method will return the result immediately. The isFetchingData will be false most of the time.

Meteor.call('method.call', inputs, (error, result) => {
    this.setState({isFetchingData: false});
    /* do what you want to do with the result here */
});
1 Like

Do you know of any good examples of async/await being using in Meteor like that? Would it be done on client or the server? I saw some examples of this online, but they weren’t very clear.

This article may help:

Funnily enough, this was the article I’d read initially, but and while it’s a good intro to async/await, I’m still confused as to how to use it in the case of an event.

To be specific, my code looks like this:

Template.booking.events({
  'click #submit'(event){ 
   ...STUFF HAPPENS HERE...      
      Meteor.call('sendBooking', timestart, timeend, summary, description, (error, result) =>
        {
             console.log("Results: "+ result); <-- THIS IS THE RESULT THAT NEEDS TO BE ASYNCED
         }
       }
     );
    },
});

I understand I can replace that Meteor.call with the callWithPromise wrapper, but which functions/values am I async/await-ing?

In your example, you would start a loading spinner, send off the call, and then when you get the result, stop the spinner.

Template.booking.onCreated(function() {
  this.loading = new ReactiveVar(false);
});

Template.booking.events({
  'click #submit'(event, instance){ 
   ...STUFF HAPPENS HERE...      
      instance.loading.set(true)
      Meteor.call('sendBooking', timestart, timeend, summary, description, (error, result) =>
        {
             console.log("Results: "+ result); <-- THIS IS THE RESULT THAT NEEDS TO BE ASYNCED
             // Do something with the result
             instance.loading.set(false);
         }
       }
     );
    },
});
{{#if isLoading }}
  <div class="loading-spinner"></div>
{{else}}
  <!-- Show results here or something?
{{/if}}

So for the record, because of my time constraints with this particular project, I used a couple of work arounds. Essentially, I had the server-side insert the data into a MongoDB and then had the python call update values in that same document in MongoDB when it was ready, which would include updating specific fields in the document that the client-side spinner would look for and would react accordingly.

So I dropped trying to communicate asynchronously for now, but I do intend to come back to it and learn it because it seems like a mighty useful part of Meteor to learn, especially for me as I’m often building applications that include doing work outside of meteor on the server side.

I haven’t fully figured out how to use it yet, but it seems like wrapping my calls in Fibers would’ve done the trick, but I need more time learning it. Will do it later.

Evented Mind seems to have a good course on the topic for those interested.

Thanks for everyone’s help, I’ll consider this thread solved (for now).

Template.booking.events({
  async 'click #submit'(event){ 
   ...STUFF HAPPENS HERE...      
    try {
const result = await  Meteor.callPromise('sendBooking', timestart, timeend, summary, description)
    console.log("Results: "+ result)
} catch(err) { handle error here }
    },
});

That’s all you need to do to use the async value with async/await in a async function since await basically makes the promise resolve synchronously within the function.