jQuery Validation Wait Ajax Complete Before Submitting Form

A tip of jQuery Validation

A. Using Option async of Ajax

To combine Ajax with jQuery Validation, it is easy to tell that we can put ajax function into jQuery Validation custom method and then return true or false based on Ajax function call-back value. However, jQuery validation wil lnot wait for Ajax call-back to finish its job unless we set one option in Ajax function. The following shows this option. It is called "async".

jQuery.validator.addMethod("check_display_name_to_be_unique_action", function(value) {
  var dataString = {
    "action" : "check_display_name_to_be_unique_action",
    "display_name" : value
  };
  var check_result = false;
  jQuery.ajax({
    type: "POST",
    url: "/wp-admin/admin-ajax.php",
    async: false,
    data: dataString,
    dataType: "json",
    success: function(return_data){
      if (return_data["success"] == "0") {
        check_result = false;
      } else if(return_data["success"] == "1") {
        check_result = true;
      }
    }
  });
  return check_result;
}, "error message");

From above code, we see ajax call function is place inside the validation custom method. And "async" is set to false to make sure validation check will not finish until we have ajax call-back return.

It is also the best practice to add "error" state check in ajax return, which is not displayed in the above code.

B. Using when Function

jQuery now defines a when function for this purpose.

It accepts any number of Deferred objects as arguments, and executes a function when all of them resolve.

That means, if you want to initiate (for example) four ajax requests, then perform an action when they are done, you could do something like this:

$.when(ajax1(), ajax2(), ajax3(), ajax4()).done(function(a1, a2, a3, a4){
  // the code here will be executed when all four ajax requests resolve.
  // a1, a2, a3 and a4 are lists of length 3 containing the response text,
  // status, and jqXHR object for each of the four ajax calls respectively.
});
function ajax1() {
  // NOTE:  This function must return the value
  //        from calling the $.ajax() method.
  return $.ajax({
    url: "someUrl",
    dataType: "json",
    data:  yourJsonData,
    ...
  });
}

It makes for a clean and clear syntax, and avoids involving any global variables such as ajaxStart and ajaxStop, which could have unwanted side effects as your page develops.

If you don't know in advance how many ajax arguments you need to wait for (i.e. you want to use a variable number of arguments), it can still be done but is just a little bit trickier.

See Pass in an array of Deferreds to $.when() (and maybe jQuery .when troubleshooting with variable number of arguments).

If you need deeper control over the failure modes of the ajax scripts etc., you can save the object returned by .when() - it's a jQuery Promise object encompassing all of the original ajax queries. You can call .then() or .fail() on it to add detailed success/failure handlers.

C. Using remote Rule

jQuery validation plugins has a validation rule called "remote" which can be used to make an ajax request instead of specifying a custom rule which has an ajax call it in. This will save you heaps of time with those custom validation rules.

As you can see to pass through data you can simply use the key pair syntax so the request sent below the data is "&emails=email@jquery4u.com". The return values for your backend script is either json encoded true for a validation pass or html msg for validation fail.

//validate user email
$(':input[name="uAcc"]').rules("add",
{
  "remote" :
  {
    url: 'validateEmail.php',
    type: "post",
    data:
    {
      emails: function()
      {
        return $('#register-form :input[name="email"]').val();
      }
    }
  }
});

Example

/* register script */
(function($,W,D,undefined)
{
  $(D).ready(function()
  {
    //form validation rules
    $("#register-form").validate({
      rules:
      {
        email:
        {
          required: true,
          email: true,
          "remote":
          {
            url: 'validateEmail.php',
            type: "post",
            data:
            {
              email: function()
              {
                return $('#register-form :input[name="email"]').val();
              }
            }
          }
        },
        name:
        {
          required: true,
          minlength: 3
        },
        password:
        {
          required: true,
          minlength: 8
        },
        password_repeat:
        {
          required: true,
          equalTo: password,
          minlength: 8
        }
      },
      messages:
      {
        email:
        {
          required: "Please enter your email address.",
          email: "Please enter a valid email address.",
          remote: jQuery.validator.format("{0} is already taken.")
        },
        name: "Please enter your name.",
        password: "Please enter a password.",
        password_repeat: "Passwords must match."
      },
      submitHandler: function(form)
      {
        form.submit();
      }
    });
  });
})(jQuery, window, document);

Stopping remote validation as you type

By default the validation plugin will send off an ajax request for a remote rule every key you press causing too many ajax requests being sent to validate fields. One way to disable this is to deactivate the onkeyup validation so that the remote rule is only validated via ajax once you have finished typing into the input.

$("#register-form").validate({
  onkeyup: false //turn off auto validate whilst typing
});

Comments

Popular posts from this blog

Reduce TIME_WAIT Socket Connections