jquery验证不等待远程验证返回true,认为表单有效

时间:2011-08-30 17:25:38

标签: jquery jquery-validate

$("#new_component_form").validate({
  errorClass: 'input-error',
  rules : {
    "comp_data[account_name]" : {
      required: true,
      remote: {
        url: "/validate",
        data: {
          provider: 'twitter'
        }
      }
    }
  },
  onsubmit: true,
  onfocusout: false,
  onkeyup: false,
  onclick: false
});



 $("#new_component_form").submit(function(){
    console.log($(this).valid());

即使值无效,也会输出true。我看到验证最终失败并显示错误消息,但表单仍然提交。

8 个答案:

答案 0 :(得分:27)

从jQuery Validate 1.11.1开始(可能更旧),接受的答案不起作用。此外,这个问题没有简单的答案,解决方案需要在jQuery Validation中添加自定义验证方法。

实际上,简单的答案可能只是:如果您只想提交表单,请不要手动拨打valid()。只需让Validate插件为您完成。在内部,它将等待所有异步请求完成,然后才允许提交表单。只有在您手动检查valid()element()

时才会出现此问题

但是,有很多原因可能导致您需要这样做。例如,我正在处理的页面需要在启用表单的其余部分之前使用远程验证器检查字段的有效性。我可以手工完成而不是使用jQuery Validation,但这是一种重复工作。

那么,为什么设置async: false不起作用?如果将async设置为false,则同步进行,但插件无法正确处理。内部remote函数始终返回"pending",即使请求已完成并收到错误响应,也会导致valid()函数返回true 它不会检查响应的值,也不会在以后显示错误。

使用同步回调时使valid()element()同步运行的解决方案是添加自定义验证方法。我自己试过这个,看起来效果很好。您可以从常规远程验证中复制源代码并修改它以处理同步aj​​ax调用,并且默认情况下是同步的。

v1.11.1中远程函数的源代码从jquery.validate.js的第1112行开始:

remote: function( value, element, param ) {
    if ( this.optional(element) ) {
        return "dependency-mismatch";
    }

    var previous = this.previousValue(element);
    if (!this.settings.messages[element.name] ) {
        this.settings.messages[element.name] = {};
    }
    previous.originalMessage = this.settings.messages[element.name].remote;
    this.settings.messages[element.name].remote = previous.message;

    param = typeof param === "string" && {url:param} || param;

    if ( previous.old === value ) {
        return previous.valid;
    }

    previous.old = value;
    var validator = this;
    this.startRequest(element);
    var data = {};
    data[element.name] = value;
    $.ajax($.extend(true, {
        url: param,
        mode: "abort",
        port: "validate" + element.name,
        dataType: "json",
        data: data,
        success: function( response ) {
            validator.settings.messages[element.name].remote = previous.originalMessage;
            var valid = response === true || response === "true";
            if ( valid ) {
                var submitted = validator.formSubmitted;
                validator.prepareElement(element);
                validator.formSubmitted = submitted;
                validator.successList.push(element);
                delete validator.invalid[element.name];
                validator.showErrors();
            } else {
                var errors = {};
                var message = response || validator.defaultMessage( element, "remote" );
                errors[element.name] = previous.message = $.isFunction(message) ? message(value) : message;
                validator.invalid[element.name] = true;
                validator.showErrors(errors);
            }
            previous.valid = valid;
            validator.stopRequest(element, valid);
        }
    }, param));
    return "pending";
}

注意即使ajax调用完成,它总是返回“pending”。

要解决此问题,请进行以下修改:

  1. valid变量的声明移到ajax调用和success函数之外,以便进行闭包,并为其指定默认值“pending”。
  2. valid变量的旧声明更改为作业。
  3. 返回valid变量而不是常量“待定”。
  4. 这是插件插件的完整代码。只需将其保存为js文件,并在包含jQuery验证后将其包含在页面或模板中:

    //Created for jQuery Validation 1.11.1
    $.validator.addMethod("synchronousRemote", function (value, element, param) {
        if (this.optional(element)) {
            return "dependency-mismatch";
        }
    
        var previous = this.previousValue(element);
        if (!this.settings.messages[element.name]) {
            this.settings.messages[element.name] = {};
        }
        previous.originalMessage = this.settings.messages[element.name].remote;
        this.settings.messages[element.name].remote = previous.message;
    
        param = typeof param === "string" && { url: param } || param;
    
        if (previous.old === value) {
            return previous.valid;
        }
    
        previous.old = value;
        var validator = this;
        this.startRequest(element);
        var data = {};
        data[element.name] = value;
        var valid = "pending";
        $.ajax($.extend(true, {
            url: param,
            async: false,
            mode: "abort",
            port: "validate" + element.name,
            dataType: "json",
            data: data,
            success: function (response) {
                validator.settings.messages[element.name].remote = previous.originalMessage;
                valid = response === true || response === "true";
                if (valid) {
                    var submitted = validator.formSubmitted;
                    validator.prepareElement(element);
                    validator.formSubmitted = submitted;
                    validator.successList.push(element);
                    delete validator.invalid[element.name];
                    validator.showErrors();
                } else {
                    var errors = {};
                    var message = response || validator.defaultMessage(element, "remote");
                    errors[element.name] = previous.message = $.isFunction(message) ? message(value) : message;
                    validator.invalid[element.name] = true;
                    validator.showErrors(errors);
                }
                previous.valid = valid;
                validator.stopRequest(element, valid);
            }
        }, param));
        return valid;
    }, "Please fix this field.");
    

    我用我自己的表单对它进行了测试,效果很好。在启用表单的其余部分之前,我可以测试元素的有效性。但是,您可能希望设置onkeyup: false以防止在每次按键时执行同步回调。我也想使用onfocusout: false

    要使用此功能,只需将验证设置中的“remote”替换为您要使用此处的“synchronousRemote”。例如:

    $("#someForm").validate({
        rules: {
            someField: {
                required: true,
                synchronousRemote: {
                        url: "/SomePath/ValidateSomeField"
                        //notice that async: false need not be specified. It's the default.
                }
            }
        },
        messages: {
            someField: {
                required: "SomeField is required.",
                synchronousRemote: "SomeField does not exist."
            }
        },
        onkeyup: false,
        onfocusout: false
    });
    

答案 1 :(得分:6)

陷入同样的​​问题似乎你已经设置了对同步的远程调用 - async:false

否则$("form").valid()将返回true以进行远程验证,请参阅下面的内容

rules: {
    NameToValidate: {
        required: true,
        remote: function()
        {
            return {
            type: "POST",
            async: false,
            url: "www.mysite.com/JSONStuff",
            contentType: "application/json; charset=utf-8",
            dataType: "json",
            data: JSON.stringify( {
                Name: "UNIQUE NAME"
            } )
        }
    }
},
.....

答案 2 :(得分:6)

这是我们在项目中提出的解决方案。

from scrapy.item import Item, Field

class FinAidScraperItem(Item):
    # define the fields for your item here like:
    url=Field()
    linkedurls=Field()
    internal_linkedurls=Field()
    external_linkedurls=Field()
    http_status=Field()
    title=Field()
    text=Field()

这利用了$(“#form”)。validate()。pendingRequest将始终为>的事实。只要有远程验证,就为0。

注意:这不适用于在远程请求中设置var validPendingTimeout; function doSomethingWithValid() { var isValid = $("#form").valid(); var isPending = $("#form").validate().pendingRequest !== 0; if (isPending) { if (typeof validPendingTimeout !== "undefined") { clearTimeout(validPendingTimeout); } validPendingTimeout = setTimeout(doSomethingWithValid, 200); } if (isValid && !isPending) { // do something when valid and not pending } else { // do something else when not valid or pending } }

答案 3 :(得分:5)

解决此问题的最简单方法(在此处报告:https://github.com/jzaefferer/jquery-validation/issues/361)是检查表单是否有效两次:

if (myForm.valid() && myForm.valid()) {
    ...
}

将远程规则设置为async:false并使用valid()检查有效性实际上等待完成的调用,但不使用它们的返回值。再次致电valid()会将其考虑在内。

有点难看,但它有效。我正在使用jquery 2.1.0和jquery-validation 1.11.1,BTW。

答案 4 :(得分:0)

如果验证返回false,则必须停止浏览器的正常提交。

$("#new_component_form").submit(function() {
    if ($(this).valid())) {
        console.log("I'm a valid form!");
    } else {
        console.log("I'm NOT a valid form!");
        //Stop the normal submit of the browser
        return false;
    }
}

答案 5 :(得分:0)

我知道这是补丁,但是 我通过检查当前的ajax是否已解决来解决它

我通过$.active检查当前的ajax调用,如果没有运行ajax,它将给您0

$('#frmControlFamily #Identifier').valid();            
if ($.active == 0) {
    // my save logic
}

答案 6 :(得分:0)

您可以两次验证表单,也可以检查当前的ajax调用是否完成。

if (myForm.valid() && myForm.valid()) {

}

if ($.active == 0) {

}

到目前为止,我发现的最佳解决方案已在该线程的顶部提到。 https://stackoverflow.com/a/20750164/11064080

但是没有适当的解决方案。如果您以相同的形式使用两个远程验证功能,则上述所有方法都会失败。

答案 7 :(得分:0)

我通过创建一个自定义函数来检查Dim db As Database Set db = CurrentDb Dim QueryString As String Dim QDDocsCross As QueryDef Set QDDocsCross = db.CreateQueryDef("DocsCross") QueryString = "TRANSFORM COUNT(Docs.Document) AS CountOfDocument " & _ "SELECT Docs.[Contractor Dept], " & _ "COUNT(Docs.Document) AS [Total Of Document] " & _ "FROM Docs " & _ "GROUP BY Docs.[Contractor Dept] " & _ "PIVOT Docs.[Engineering Status Code]" QDDocsCross.SQL = QueryString $("#form").valid()来解决了这个问题:

$("#form").validate().pendingRequest

这是基于function formIsValid() { return $("#form").valid() && $("#form").validate().pendingRequest === 0; } 验证请求期间$("#form").validate().pendingRequest始终大于0的假设而进行的。使用jquery-validation 1.19.1可以正常工作。