1

I'm using the jQuery validation plugin. It works great, an impressive tool. A couple of the 88 fields on the form I've got need to use APIs on other websites. I already found that I can't do that directly from javascript because it violates the same origin policy. So instead, it makes $.ajax calls to my own website (which, in turn invokes the APIs through curl).

The jQuery validation plugin lets you define validation methods by calling jQuery.validator.addMethod(name, method [, message ] )

The name is a string that will be used to identify the function to be called for a particular field specified in the configuration. The method is a function definition returning a boolean, and parameters consisting of the field's current value, the DOM element for the field, and params to be passed to the method.

So in my validation method, I need to make a $ajax call, process the result, and return true or false to my caller. I don't get to tell my caller to pass me functions to call for valid or invalid, I have to return a boolean to my caller. I've read the answers to this question and others like it, and as far as I can tell, all of them involve triggering a call to another function with the result of the $.ajax() call (whether using promises or callbacks) - none of them get the result back to the caller of $.ajax(), unless you pass async: false to $.ajax(). Am I missing something? Or should I tell the maintainers of the plugin that they defined a poor interface for custom validation functions :-)?

sootsnoot
  • 2,178
  • 3
  • 22
  • 27
  • Please update with actual code and HTML/CSS you have tried with the one challenge it presents you so we can best assist you here. – Mark Schultheiss Jan 23 '23 at 22:23
  • One key with jQuery `$.ajax()` is that it returns a promise and you can handle that in the `.done(function(data){});` method ref: https://api.jquery.com/jquery.ajax/ – Mark Schultheiss Jan 23 '23 at 22:28
  • @Mark Schultheiss But the function passed to .done() cannot cause the caller of $.ajax() to return a specific value, can it? – sootsnoot Jan 24 '23 at 03:50
  • I guess I can add some code, but I don't see how HTML or CSS would be relevant. What's relevant is the interface for validation methods used by the plugin. The answer by ruleboy21 shows that he fully understood the question as written, and it's a great answer. If I do post some code, will you promise to show how it can be done without using async: false, and without using his answer suggesting use of the "remote" validation method built-in to the jQuery validation plugin? – sootsnoot Jan 24 '23 at 04:13
  • jquery ajax 1`.done()` is called when the ajax returns/completes being passed the returned values - which you then do what you wish with - you can even trigger a custom event like "all-validated" or some such within it (or after all validations have completed). – Mark Schultheiss Jan 24 '23 at 15:01
  • @Mark Schultheiss But calling another function, whether it's one passed to $.ajax.done(), or one triggered by a custom event, cannot change the value being returned from a validation function I write that is called from the bowels of the jQuery validation plugin, can it? The answer by ruleboy21 kinda confirms that: to write a validation method that relies on the output from another server (which is what $.ajax() gives you), you have to use the plugon's builtin "remote" method and do the validation on a server. In my case, it would be my own server using curl to query a different server. – sootsnoot Jan 24 '23 at 19:22
  • The builtin "remote" method of the plugin is then free to process the ajax call it makes asynchronously, making changes to the DOM to reflect valid/invalid whenever its ajax call completes. – sootsnoot Jan 24 '23 at 19:26

1 Answers1

1

There is no need to define a custom rule for this. "jQuery validation" already has a built in remote method for such a scenario. Try this

Example 1: Makes the email field required, an email and does a remote request to check if the given address is already taken.

$( "#myform" ).validate({
  rules: {
    email: {
      required: true,
      email: true,
      remote: "check-email.php"
    }
  }
});

Example 2: Makes the email field required, an email and does a remote request to check if the given address is already taken. In addition, the http method is set to "post" and the username is sent alongside the email address.

$( "#myform" ).validate({
  rules: {
    email: {
      required: true,
      email: true,
      remote: {
        url: "check-email.php",
        type: "post",
        data: {
          username: function() {
            return $( "#username" ).val();
          }
        }
      }
    }
  }
});

The remote method in the above example is what you're looking for. The value of the remote property accepts the same properties as that of jQuery's $.ajax() method.

On the server, you can return "true" to indicate that the validation passed, "false" for fail or a string to display a custom error message.

ruleboy21
  • 5,510
  • 4
  • 17
  • 34
  • But I guess this lets the designer of this marvelous plugin off the hook for the interface requiring that custom validation functions return a true or false value, meaning that they can't contain $.ajax() calls. If your validation method needs to call a remote API, then you must use the remote validation method, period. And no matter where or what the remote API is, you can always write code on your server to implement it. Thanks! – sootsnoot Jan 24 '23 at 04:03
  • I got it working, and so I've marked this as the accepted answer, thanks! AFAICT, there is no other way to do it (other than async: false , which I had previously been using). Do you agree? If so, it would be nice if the plugin documentation made a note of this, that you can't use $.ajax() within a custom validation method unless you use async:false, and in order to avoid doing that, you must use the builtin "remote" method. Also nice if the document gave a more complete description of "remote". It only gives examples, which are somewhat ambiguous. – sootsnoot Jan 26 '23 at 17:02
  • 1
    I 100% agree. `async: false` will make the custom validation work synchronously which is in line with how all the other rules work. _"Note that synchronous requests may temporarily lock the browser, disabling any actions while the request is active"_. The `remote` rule on the other hand is for making synchronous calls. – ruleboy21 Jan 26 '23 at 17:14
  • You meant to say "The `remote` rule makes asynchronous calls", right? – sootsnoot Jan 26 '23 at 17:27