Fixing a delayed callback causing false errors in

2019-05-29 14:17发布

So here's my problem.

I'm currently working on a PhoneGap application using jQuery Mobile and the Validation jQuery plugin for form validation.

I'm trying to set up a custom rule so that it will check to see if a name is already in the database, and if so, prevent the form from being submitted until the user chooses a name that is unique.

The problem is one that I've encountered before but have not yet managed to properly solve. When I call the method that executes the SQL select statement, the success callback does not get completed until after the validator has already completed and thrown false. This means that if a user enters a unique name, it will display an error, but if the user forces it to re-validate the fields, it will then be valid because the success callback had, in the meantime, completed.

Here's the relevant code:

var nameUnique;

jQuery.validator.addMethod("nameIsUnique", function(value, element) {
        checkNameSQL();
        return this.optional(element) || nameUnique;
    }, "This name is already in use. Please choose another.");

$('#createForm').validate({
    rules: {
      createName: {
        required: true,
        nameIsUnique: true
      },
      createDescription: {
        required: true
      }
    },
    //snip//
});

function checkNameSQL()
{
var name =   document.forms['createForm'].elements['createName'].value;
if (!(name == null || name == ""))
{
    dbShell.transaction(function(tx) {
       tx.executeSql("SELECT STATEMENT",[name],function(tx,results){if(results.rows.length==0){nameUnique = true;}},errorHandler)
    },errorHandler);
}
}

I've simplified it where it makes sense, cutting out code not relevant to the question. As you can see, I call the method to check if the name exists, but before the success callback function triggers to set nameUnique to true, it's being returned by the validator, causing a false error.

How should I change my code to prevent this from occurring? What general programming practices should I follow to circumvent similar problems in the future? Thanks!

1条回答
兄弟一词,经得起流年.
2楼-- · 2019-05-29 14:50

You can return pending as a value from the addMethod() besides true and false which can be used to delay the validation. For more info you can check the source of validation library.

Try this way:

$.validator.addMethod("nameIsUnique", function(value, element) {
    var validator = this;
    var previous = this.previousValue(element);
    checkNameSQL(value, function(status) {
        var valid = status === true;
        if (valid) {
            var submitted = validator.formSubmitted;
            validator.prepareElement(element);
            validator.formSubmitted = submitted;
            validator.successList.push(element);
            validator.showErrors();
        } else {
            var errors = {};
            var message = status || validator.defaultMessage(element, "remote");
            errors[element.name] = previous.message = $.isFunction(message) ? message(value) : message;
            validator.showErrors(errors);
        }
        previous.valid = valid;
        validator.stopRequest(element, valid);
    });
    return "pending";
}, "This name is already in use. Please choose another.");

function checkNameSQL(name, callback) {
    if (!(name == null || name == "")) {
        dbShell.transaction(function(tx) {
            tx.executeSql("SELECT STATEMENT", [name], function(tx, results) {
                if (results.rows.length == 0) {
                    nameUnique = true;
                    callback(true);
                }else{
                    callback(false);
                }
            }, errorHandler)
        }, errorHandler);
    }
}

For demo check this fiddle - http://jsfiddle.net/dhavaln/GqsVt/

查看更多
登录 后发表回答