Meteor.users.find not synchronous inside Meteor.call when inside an event hook of a jquery plugin


#1

Greetings Fellow Meteorites,
I am using a jquery plugin (called Bootstrap Wizard and initializing it inside onRendered hook of a blaze template.
The jquery plugin has an event onNext if true is returned the wizard continues, if false is returned, it halts.
The initialization:
Template.getting_started_wizard.onRendered(function(){ let continue = false $('#getting-started-wizard').bootstrapWizard({ onNext: function(tab, navigation, nextIndex){ if(nextIndex === 1){ Meteor.call('testing', function(error,response){ if(error){ sAlert.error(error.reason); } else{ if(response && response === true){ continue = true } else{ continue = false } } }); return continue } ... } // end onNext }); });

The Meteor method is a very simple users find (which is supposed to be synchronous.)
Here’s the method :
Meteor.methods({ 'testing' : function(){ const userId = Meteor.userId(), query = { _id: userId, "services.twitter": { "$exists" : true } }, userResult = Meteor.users.findOne() if(userResult){ return true } else{ return false } } });

The onNext doesn’t wait for the (what should be) synchronous Meteor.call(‘testing’) so ends up returning false (and the wizard doesn’t proceed) even when the Meteor method does in fact return true (and hence the wizard should be moving forward)

Does anyone have any ideas here ??? Would appreciate the help big time! Sorry the code is not formatting properly
Thank you.
Alex


#2

This is never going to work as you expect it to. Meteor.call is asynchronous (as you have identified), but that means that your code continues to run at the statement following the call while the async activity occurs. So, what your code looks like is:

Template.getting_started_wizard.onRendered(function () {
  let continue = false;
  $('#getting-started-wizard').bootstrapWizard({
    onNext: function (tab, navigation, nextIndex) {
      if (nextIndex === 1) {
        // Meteor.call(...)
        return continue
      }
    } // end onNext
  });
});

Basically, if nextIndex is 1 it returns false, otherwise it returns undefined. When the callback eventually executes it has no effect you can act on.

(BTW, continue is a reserved word in JavaScript - my linter was seriously upset - you may want to consider a different name. :slight_smile: )


#3

@robfallows Thanks for the reply. You are active on these forums :slight_smile: I was under the impression the Meteor.users.find (inside a meteor method) would make that method synchronous no?

I did try using both fibers/future and using Meteor’s wrapAsync to make it synchronous but to no avail.

Alex


#4

You are able to write synchronous-style code on the server using minimongo commands, which means that you can write linear code and hide any async nastiness. That means that your server code appears to run synchronously. That’s all done for you with Fibers/Futures under the hood.

On the client, you don’t have that luxury - although you can wrap a Meteor.call in a Promise, which, when coupled with async/await gives you many of the benefits of linear code. However, unless you can promisify your complete code path you will at some point end up resorting to a final somePromise.then() which basically means you have to get back into async mode in order to finish.

One option that you may be able to get to work is to use reactive variables and autorun to control the flow of an external package (I know nothing about the package you’re wanting to use).

Long story short: the client runs asynchronously and you have to write your code accordingly.


#5

Thanks for your help! I a’m going to begin switching over to material-ui and gradually start incorporating react into blaze until my app becomes full react. Material UI has some amazing out of the box components I can’t resist. :heart_eyes: :heart_eyes: