jqeury validate 相同name值的解决办法

前一段时间学习了jquery validate 的使用,还满心欢喜的觉得以后终于可以规范化的去写表单验证了。不然,碰到使用validate 检查相同name 值的问题着实难到我了。

juqery validate 自打设计之初就没想着能够验证表单中多个name 值相同的字段,以至于连官方源码中都有这么一句:

// Select only the first element for each name, and only those with rules specified
if ( name in rulesCache || !validator.objectLength( $( this ).rules() ) ) {
    return false;
}

Select only the first element for each name, and only those with rules specified

找了半天bug的我此时的心是崩溃的,但是也只能不断找解决办法(得亏我有一颗作死的心)。

经过资料的查阅和源码的解读,这段代码是这样的(位于源码的615-643):

elements: function() {
    var validator = this,
        rulesCache = {};

    // Select all valid inputs inside the form (no submit or reset buttons)
    return $( this.currentForm )
    .find( "input, select, textarea, [contenteditable]" )
    .not( ":submit, :reset, :image, :disabled" )
    .not( this.settings.ignore )
    .filter( function() {
        var name = this.name || $( this ).attr( "name" ); // For contenteditable
        if ( !name && validator.settings.debug && window.console ) {
            console.error( "%o has no name assigned", this );
        }

        // Set form expando on contenteditable
        if ( this.hasAttribute( "contenteditable" ) ) {
            this.form = $( this ).closest( "form" )[ 0 ];
        }

        // Select only the first element for each name, and only those with rules specified
        if ( name in rulesCache || !validator.objectLength( $( this ).rules() ) ) {
            return false;
        }

        rulesCache[ name ] = true;
        return true;
    } );
},

其中有这么一句:

var name =  this.name || $(  this  ).attr(  "name"  );  // For contenteditable

name等于当前元素的name属性,然后再看会发现底部的rulesCache 是一个缓存,采用一个闭包的形式长驻内存。

// Select only the first element for each name, and only those with rules specified
if ( name in rulesCache || !validator.objectLength( $( this ).rules() ) ) {
    return false;
}

再回到这个判断,如果当前name已经存在rulesCache 中,则直接返回false,就跳过不检查了。总算是明白那句它头上那行注释的原因了。

那么,接下来的问题就是:怎么解决它?

其实就是把这一句

var name = this.name || $( this ).attr( "name" ); // For contenteditable

改成:

var name = this.id || this.name || $( this ).attr( "name" ); // For contenteditable

优先使用id 来赋值name 就行了。
以为这就完了?还是太天真。到了这一步,成功了一大半,但是并不完美。插件已经能够检测相同name 表单字段,但是,默认的表单聚焦永远都只会出现在相同name 字段的第一个。抓狂啊啊啊。或许你会想直接丢弃表单聚焦,但是我就不!继续跟你作!

再看文档会发现validate 有个配置参数showErrors,通过赋值一个函数来决定检测到表单错误的提示:

showErrors:function(errorMap,errorList) {
    if(errorList.length){
        errorList[0].element.focus();
    }
    this.defaultShowErrors();
},

稍微解释一下,函数的两个参数,errorMap是每个对应错误表单字段的提示信息数组,errorList 是带有字段dom值和其他一些信息的数组。所以这里就直接通过取出errorList 中的第一个数据的dom对象,聚焦,完事。

别着急→_→ ,其实还没完,这里外层需要一个if 来判断errorList 的长度是否为1,因为在你输入表单的过程中,validate 会不断调用这个函数,如果你不判断,就是一堆的报错信息。

大功告成,再来说一下最后那句

this.defaultShowErrors();

这句的意思就是调用插件原生的错误显示方式,当然你不喜欢可以去掉,自己随便写。

最后,希望大家在jqeury validate的坑中学到知识。顺便贴上一段不用修改源代码文件的方法:

if($.validator){
    $.validator.prototype.elements = function () {
        var validator = this,
        rulesCache = {};
        // Select all valid inputs inside the form (no submit or reset buttons)
        return $( this.currentForm )
        .find( "input, select, textarea, [contenteditable]" )
        .not( ":submit, :reset, :image, :disabled" )
        .not( this.settings.ignore )
        .filter( function() {
            var name = this.id || this.name || $( this ).attr( "name" ); // For contenteditable
            if ( !name && validator.settings.debug && window.console ) {
                console.error( "%o has no name assigned", this );
            }
            // Set form expando on contenteditable
            if ( this.hasAttribute( "contenteditable" ) ) {
                this.form = $( this ).closest( "form" )[ 0 ];
            }
            // Select only the first element for each name, and only those with rules specified
            if (name in rulesCache || !validator.objectLength( $( this ).rules() ) ) {
                return false;
            }
            rulesCache[ name ] = true;
            return true;
        } );
    }
}

你可能感兴趣的:(javascript,jquery,validate)