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

ore*_*ake 22 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());
Run Code Online (Sandbox Code Playgroud)

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

Gla*_*zed 28

从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";
}
Run Code Online (Sandbox Code Playgroud)

注意即使ajax调用完成,它总是返回"pending".

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

  1. valid变量的声明移到ajax调用和success函数之外,以便进行闭包,并为其指定默认值"pending".
  2. valid变量的旧声明更改为赋值.
  3. 返回valid变量而不是常量"pending".

这是插件插件的完整代码.只需将其保存为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.");
Run Code Online (Sandbox Code Playgroud)

我用自己的形式对此进行了测试,效果很好.在启用表单的其余部分之前,我可以测试元素的有效性.但是,您可能希望设置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
});
Run Code Online (Sandbox Code Playgroud)

  • 你认为这是jQuery Validate中的一个错误吗? (2认同)
  • 我不认为这本身就是一个错误,而是一个带有负面后果的设计选择.他们肯定知道当提交表单时异步远程验证器工作时他们在做什么.我不知道为什么他们没有给我们选择在我们需要的时候指定`async:false`.也许他们不想让开发人员有机会通过使它同步并留下`onkeyup:true`来破坏用户界面.想象一下每次击键都会延迟1秒.但是如果检测到另一个按键,可能有一种方法可以中止同步ajax请求.我不确定. (2认同)
  • @mevernom我建议编辑,但我被拒绝了.只需在成功回调中验证失败时添加此行:that.settings.messages [element.name] .synchronousRemote = message; (2认同)

Bog*_*dan 7

陷入同样的​​问题似乎你已经设置了对synchronous的远程调用 - 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"
            } )
        }
    }
},
.....
Run Code Online (Sandbox Code Playgroud)

  • 这不起作用.至少不在v1.11.1中.在内部,远程方法总是返回"挂起"`(不是真或假),所以即使验证是同步执行的,验证框架也不会在手动调用`valid()`和`valid()时将其视为`将永远返回true.但是,在实际提交表单时,它始终是同步的:表单提交将被抑制,直到所有异步请求完成.因此,即使您将请求设置为同步,也绝不会导致`valid()`返回`false`.您需要修改源来实现这一点. (2认同)

emi*_*ast 6

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

if (myForm.valid() && myForm.valid()) {
    ...
}
Run Code Online (Sandbox Code Playgroud)

async:false使用valid()实际等待调用完成来设置远程规则并检查有效性,但不使用它们的返回值.valid()再次呼叫将它们考虑在内.

有点难看,但它的工作原理.我正在使用jquery 2.1.0和jquery-validation 1.11.1,BTW.


Pau*_* B. 6

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

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
  }
}
Run Code Online (Sandbox Code Playgroud)

这利用了$("#form").validate().pendingRequest在远程验证时总是> 0的事实.

注意:这不适async: true用于远程请求中的设置.


Gil*_*ert 5

我通过创建一个自定义函数来检查$("#form").valid()和解决这个问题$("#form").validate().pendingRequest

function formIsValid() {
    return $("#form").valid() && $("#form").validate().pendingRequest === 0;
}
Run Code Online (Sandbox Code Playgroud)

这适用于$("#form").validate().pendingRequestremote验证请求期间始终 > 0的假设。这使用 jquery-validation 1.19.1 工作。