posabsolute / jQuery-Validation-Engine

jQuery form validation plugin
http://www.position-absolute.com/articles/jquery-form-validator-because-form-validation-is-a-mess/
2.57k stars 1.2k forks source link

Form validation returns false when ajax validation returns true #954

Open bartclaeys opened 6 years ago

bartclaeys commented 6 years ago

Using version 2.6.5 the below form validation returns false even if all fields are correctly validated (no red bubbles). The problem is, when ajax validation happens (checking whether username exists) a green bubble appears which is considered an error and the script returns 'false'.

var result = form.validationEngine('validate');

The field that causes the problem:

<form role="form" id='signup' method='post' action='/signup/'>
<input type='text' name='username' value='' id='username' class='validate[required,custom[onlyLetterNumber],minSize[6],maxSize[20],ajax[validationEngine_UsernameJson]]'/>
</form>
bartclaeys commented 6 years ago

When validating a field with AJAX the following things happen:

  1. validationEngine makes an AJAX call and a JSON object is returned with a status.
  2. validationEngine captures a return message, either preset in rules, or returned by the JSON object.

The status is only being used to display the bubble in red or green, but it is not passed through otherwise. The return message (regardless of success or failure) is always interpreted as a validation error.

First step is to avoid interpreting the return message as an error, by changing the _validateField method. Change following:

case "ajax":
    // AJAX defaults to returning it's loading message
    errorMsg = methods._ajax(field, rules, i, options);
    if (errorMsg) {
        promptType = "load";
}

Into this:

case "ajax":
    errorMsg = methods._ajax(field, rules, i, options, function(errorMsg) {
        if (errorMsg) {
            promptType = "load";
        }

        if(errorMsg.isError==false) {
            errorMsg.status = '_break';
        }
    });

What we've done here is capture an object rather than a string. This object passes the JSON status through the isError variable. Then, we evaluate the status and force a status _break which is (oddly enough) the way validationEngine interpretes the field has validated successfully.

Next we need to change the _ajax method to return this object. Replace this:

_ajax: function(field, rules, i, options) {

Into this:

_ajax: function(field, rules, i, options, callback) {

Then find and remove this:

return rule.alertTextLoad;

And right after errorField.trigger("jqv.field.result", [errorField, options.isError, msg]); add this:

var obj = {alertTextLoad: rule.alertTextLoad, isError: !status};
callback(obj);

So, rather than returning just the return message (alertTextLoad), we return an object when the AJAX call is successfully completed,

bartclaeys commented 6 years ago

The above is half the solution, I'll update when I successfully complete the other part. The other part involves passing through the AJAX return status from the _validateField method to the _validateFields method, and finally to the validate method. The problem is that it is rather complex, because all these methods need to wait until the AJAX request has been completed, and right now they don't wait at all. So they all need to be wrapped in callback functions.

marcelosboeira commented 4 years ago

did anyone find how to solve this problem? even with the change that was commented here, they are still submitting the form when they click the button :(

tarcisioq commented 3 years ago

i`m fixed that with litle change on function _ajax:

Set the $.ajax request with parameter "async" to "false" then, on result of function:

change this: return rule.alertTextLoad; to this if (options.isError) return rule.alertText;

thats it;