Using Meteor.call()... not executing function being called


#1

Hey All,

Running into another jam. I’m trying to use Meteor.call(‘methodName’, varName) syntax to call another method in my .events method. For whatever reason, I’m getting the following error:

Error invoking Method 'validateEmail': Method not found [404]

I have the following method:

Template.ForgotPassword.events({...
var isEmailValid = Meteor.call('validateEmail', email);
...
},
validateEmail: function(email) {
    var re = /^([\w-]+(?:\.[\w-]+)*)@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$/i;
    return re.test(email);
  }

From what I read in the link below (and on a few other sites), I should be able to just use:

Meteor.call('validateEmail', email); or Meteor.call('validateEmail', [email]);

When I do this, the validateEmail method is never called, so isEmailValid is undefined. What exactly am I doing wrong here?

http://meteortips.com/first-meteor-tutorial/methods/


#2

I made a slight modification to my code:

Meteor.methods({
  validateEmail: function(email) {
    var re = /^([\w-]+(?:\.[\w-]+)*)@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$/i;
    return re.test(email);
  }
});

I’m now calling the validateEmail method and the the value it returns: re.test(email) is returning true so isEmailValid should be true but it’s still undefined.

UPDATE:
I ended up making a modification to my Meteor.methods function:

Meteor.methods({
  validateEmail: function(email) {
    var re = /^([\w-]+(?:\.[\w-]+)*)@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$/i;
    return Session.set('isEmailValid', re.test(email));
  },
  
  isEmailValid: function(){
    return Session.get('isEmailValid');
  }
});

and was able to use Session.get('isEmailValid'); to check. not sure if this is good practice but it works. If anyone has a better suggestion please let me know.


#3

isEmailValid will never return anything other than undefined, because Meteor.call() is asynchronous on the client. You have to provide a reactive variable in the callback to get a return value.

Meteor.call('validateEmail', email, function (err, res) {
    if (res) {
        Session.set('isEmailValid', res);
    }
});

Alternatively you can use ReactiveDict to scope your reactive variables

Template.ForgotPassword.onCreated(function () {
    this.state = new ReactiveDict();
});

Template.ForgotPassword.events({
    'click .whatever': function (event, template) {
        Meteor.call('validateEmail', email, function (err, res) {
            if (res) {
                template.state.set('isEmailValid', res);
            }
        });
    }
});

Template.ForgotPassword.helpers({
    isEmailValid: function () {
        return Template.instance().state.get('isEmailValid');
    }
});

<template name="ForgotPassword">
    {{#if isEmailValid}}
        <!-- email valid -->
    {{/if}}
</template>


#4

Oh nice, thanks for the response. I was actually writing an update as you were posting this. I ended up taking the Session.set('isEmailValid', res); route. That made the most sense to me. Glad to know I was on the right track. Thanks again.


#5

@jwright04 you shouldn’t be using Session in Meteor.methods though. You should be using Meteor.methods for server functions. I think for what you are trying to do, you should not use Meteor.methods at all. Just do the calculation in the helper.


#6

UX tip: don’t hard-validate emails. In other words, don’t prevent someone from submitting a form with an email address that you think is invalid, because there’s always some special case you may not have covered, such as the below which are all valid (and your regex fails to match these):

It’s good practice to instead check the email entered, and suggest “are your sure your email is correct?”


#7

Thanks @ffxsam, that’s good advice, I’ll definitely make some mods on my end.


#8

@hellstad, thanks for that, I’ve been seeing a lot of examples where people are using Session.set/get. Is there a general rule of thumb for when and when not to take this approach?


#9

@jwright04 Session is easy to show examples with, that’s why it’s used so much. However for most cases, it is a lot better to scope your reactive variables to your templates using ReactiveDict as I showed above. If you really MUST use a globally scoped variable you can use Session. BTW, this is all for client-side code.

Also for most cases, you should separate your Meteor.methods into the server folder(s) of your project. I think this is a very confusing part of Meteor for beginners; as methods can be declared on the client but it’s only useful if you understand its role in latency compensation.


#10

@hellstad, thanks for the explanation. I’ll have to dig deeper into this, I’m still trying to find my way around in Meteor.