给jquery-validation插件添加控件的验证回调方法

  jquery-validation.js在前端验证中使用起来很是方便,提供的功能基本上能知足大部分验证需求,例如:一、内置了不少经常使用的验证方法;二、能够自定义错误显示信息;三、能够自定义错误显示位置;四、能够自定义验证方法;五、ajax提交验证,等等前端

  可是有时候,咱们在作项目的时候总会遇到一些特殊需求,例如,在单个控件验证结束后,根据验证的成功与否,须要调用一些本身定义的方法,这个需求貌似该插件没有提供(可能有只是我没发现),没办法, 只能看源码(这就是开源的好处啊),经过对源码的分析,找到了一种能够给指定控件添加验证回调函数的方法,虽然须要修改一部分源码,可是丝绝不影响对其以前的使用,该方法能够批量添加多个控件的验证回调函数,添加方式与添加自定义规则、自定义错误信息等相似,在阅读源码的过程当中,还发现了如何控制控件验证的事件触发,以及如何解决与My97DatePicker日期插件的冲突等问题,因此建议你们多看源码,有时候会有意外收获哦。jquery

  所以,本文包括三个方面:程序员

  1. 添加控件的验证回调函数
  2. 控制控件验证的事件触发
  3. 解决与My97DatePicker日期插件的冲突问题

     下面咱们来一步步分析:ajax

给指定控件添加自定义回调函数

  首先,要添加回调函数必须找到该插件的验证方法。其实在使用该插件的时候,从直观的操做上咱们就能够发现,控件验证的触发有多种方式,包括:控件焦点的失去,控件内容的改变(实际上是keyup),以及点击提交按钮等,相信你们都知道,这些只是表象。经查看源码,能触发验证的方法有不少,如:validate、form、checkForm和element等,但这依旧是表象,以咱们程序员的嗅觉,真正的验证函数确定只有一个,通过深刻勘察,前面每一个方法都调用了check方法,在check方法中发现一句话:app

var result = $.validator.methods[method].call(this, element.value.replace(/\r/g, ""), element, rule.parameters);

可见,这句代码就是真正调用验证逻辑的地方,所以,咱们须要将自定义的验证回调函数,放置在check方法中,修改后的代码以下(黄色部分为添加的代码):ide

check: function(element) {
                element = this.validationTargetFor(this.clean(element));

                var rules = $(element).rules();
                var dependencyMismatch = false;
                for (var method in rules) {
                    var rule = { method: method, parameters: rules[method] };
                    try {
                        var result = $.validator.methods[method].call(this, element.value.replace(/\r/g, ""), element, rule.parameters);

                        // if a method indicates that the field is optional and therefore valid,
                        // don't mark it as valid when there are no other rules
                        if (result == "dependency-mismatch") {
                            dependencyMismatch = true;
                            continue;
                        }
                        dependencyMismatch = false;

                        if (result == "pending") {
                            this.toHide = this.toHide.not(this.errorsFor(element));
                            return;
                        }

                        if (!result) {
                            this.formatAndAdd(element, rule);
                 //验证失败回调函数                   if ("invalidEventForElement" in this.settings) {
                    if (element.id in this.settings.validCallbackForElement) {     this.settings.validCallbackForElement[element.id].fail();     }                 }
return false; } } catch (e) { this.settings.debug && window.console && console.log("exception occured when checking element " + element.id + ", check the '" + rule.method + "' method", e); throw e; } } if (dependencyMismatch) return; if (this.objectLength(rules)) this.successList.push(element);
         //验证成功回调函数
          
if ("invalidEventForElement" in this.settings) {
            
if (element.id in this.settings.validCallbackForElement) { this.settings.validCallbackForElement[element.id].success(); }
          }           
return true; },

 在这里,为了和插件的其余自定义属性保持一致,咱们定义了一个对象,结构以下:函数

validCallbackForElement:{
  yourControlId1:{
       success:function(){
                 //验证成功回调
           },
           fail:function(){
                //验证失败回调
           }
      },
    yourControlId2:{
       success:function(){
                 //验证成功回调
           },
           fail:function(){
                //验证失败回调
           }
      },
}        

而后将其放入validate方法的参数中,示例以下(修改的时候将"yourControlId1"和"yourControlId2"更换成你本身的控件id):ui

$("#form1").validate({
                rules: {
                    yourControlId1: {
                        required: true
                    },
                    yourControlId2: {
                        required: true,
                        maxlength: 500
                    }
                }, //end rule
                messages: {
                    yourControlId1: {
                        required: "不能为空"
                    },
                    yourControlId2: {
                        required: "不能为空",
                        maxlength: "内容过长"
                    }
                },
                errorPlacement: function(error, element) {
                    if (element.context.name == "yourControlId1") {
                        error.appendTo(document.getElementById("yourControlId1_error"));
                    }
                    else if (element.context.name == "yourControlId2")
                        error.appendTo(document.getElementById("yourControlId2_error"));
                },
                submitHandler: function(form) {
                    ajaxSubmit();
                },
                validCallbackForElement: {
                    yourControlId1: {
                        success: function() {
                            //控件yourControlId1的验证成功回调
                        },
                        fail: function() {
                            //控件yourControlId1的验证失败回调
                        }
                    },
                    yourControlId2: {
                        success: function() {
                            //控件yourControlId2的验证成功回调
                        },
                        fail: function() {
                            //控件yourControlId2的验证失败回调
                        }
                    }
                }
            }); //end validate function

在构造函数中,会将validCallbackForElement对象合并多this.settings对象中,所以,在调用的时候须要写成:this.settings.validCallbackForElement[element.id].success();this

由于咱们不必定给全部的验证控件都添加回调函数,所以,在调用的时候须要首先判断该控件有没有对应的毁掉函数,这样,调用代码就改成:spa

if ("invalidEventForElement" in this.settings) {
  if (element.id in this.settings.validCallbackForElement) {   this.settings.validCallbackForElement[element.id].fail();   }
}

到这里,如何给指定控件添加自定义验证回调函数的问题就已经解决了。下面提供一个简单的示例:

添加控件验证回调方法的示例程序

验证触发问题

在使用jquery-validation的时候发现,在调用验证方法以前,控件的keyup和focusout事件是不能触发验证的,好比咱们打开一个页面,先不点击提交按钮,这样就不对表单进行过验证,这时候咱们把光标放在input控件上,而后什么也不写,在让该input失去焦点,此时咱们会发现,并无提示该input是必填项的错误信息,缘由在于,jquery-validation插件在验证表单的时候会将错误信息保存在errorMap这个变量中,errorMap的结构以下:

errorMap{
     yourControlId1:"必填项",
     yourControlId2:"内容过长",
     ......
}

而后将errorMap合并到this.submited对象中,在focusout和keyup事件中,会判断this.submited中是否有该控件的id,若是有才会执行验证,代码以下:

onfocusout: function(element, event) {
if (!that.checkable(element) && (element.name in that.submitted || !that.optional(element))) {
that.element(element);
}
},
onkeyup: function(element, event) {
 if (element.name in this.submitted || element == this.lastElement) { 
this.element(element);
}
},

所以,在执行表单验证后才会激活控件的focusout和keyup验证,若是你想一开始就能使focusout和keyup触发验证,能够在这里去掉红色部分的代码

以前对这一部分的描述有问题,仅仅去掉红色部分的代码并不能达到验证的目的,从源码中能够看出,jquery-validation插件的做者对这里的控制仍是比较严格的,不只依赖submitted属性,还要根据控件的值来作相应判断,可能这款插件的意图就是保证控件在没有值而且没有进行表单验证以前不调用控件的验证方法,这点经过onfocusout和onkeyup事件中的逻辑就能看出来,两处的逻辑不太同样。所以,若是想要在表单验证前就能对空值的控件经过focusout和keyup触发验证方法,那么就须要修改不少地方,这显然不符合该插件的编写思路。

与My97DatePicker日期控件的冲突问题

     相信My97DatePicker是不少人都用过的一个日期控件,该控件会与jquery-validation插件冲突,致使jquery-validation插件的focusout事件没法触发验证,多是由于这两个东西都注册了focusout事件,因此致使了冲突,原本想看看My97DatePicker的源码,打开以后发现是压缩版的,好像还进行了混淆,因此若是在页面中同时使用了这两个东西的话,只能修改jquery-validation了,能够进行以下修改:

onfocusout: function(element, event) {
                //修改了此处代码,不然会与My97DatePicker冲突,致使失去焦点的时候不会验证
                var that = this;
                setTimeout(function() {
                    if (!that.checkable(element) && (element.name in that.submitted || !that.optional(element))) {
                        that.element(element);
                    }
                }, 100);

            },
相关文章
相关标签/搜索