为新表单字段扩展jQuery表单验证脚本

时间:2012-11-21 21:42:04

标签: javascript jquery html validation

我有一个简单的HTML表单,最初是一系列问题(A1到A5和B1到B3),带有是/否的单选按钮:

<tr>
      <td width="88%" valign="top" class="field_name_left">A1</td>
      <td width="12%" valign="top" class="field_data">         
                    <input type="radio" name="CriteriaA1" value="Yes">Yes<input     type="radio" name="CriteriaA1" value="No">No</td>
</tr>

用户只能回答A系列问题或B系列问题,但不能回答两者。他们还必须完成A或B系列中的所有问题。

我现在还有一系列问题 - C1到C6 - 需要扩展我的验证脚本以确保用户输入A,B或C并回答每个系列中的所有问题。

我对A和B的原始脚本如下所示:

    $(function() {

        $("#editRecord").submit(function(){

        // is anything checked?
        if(!checkEmpty()){
            $("#error").html("Please check something before submitting");
            //alert("nothing Checked");
            return false;
        }
        // Only A _OR_ B
        if(isAorB()){
            $("#error").html("Please complete A or B, not both");
            //alert("please complete A or B, not both");
            return false;
        };
        // all A's or all B's
        if(allAorBChecked()){
            $("#error").html("It appears you have not completed all questions");
            //alert("missing data");
            return false;
        };
        if(haveNo()){
            // we're going on, but sending "type = C"
        }
        //alert("all OK");
            return true;
        });
    });


function checkEmpty(){
    var OK = false;
    $(":radio").each(function(){
        if (this.checked){
            OK = true;
        }
    });
    return OK;
}
 function isAorB(){
    var OK = false;
    var Achecked = false;
    var Bchecked = false;
    $(":radio").each(function(){
        var theChar=this.name.charAt(8);
        // if we have an A checked remember it
         if(theChar == "A" && this.checked && !Achecked){
            Achecked = true;    
        }
        if(Achecked && theChar == "B" && !Bchecked){
            if(this.checked){
                Bchecked = true;
            }
        }
        if (Achecked && Bchecked){
            OK = true;
        }
    });
    return OK;
} 
function allAorBChecked(){
    var notOK = false;
    var Achecked = false;
    $(":radio").each(function(){
        // skip through to see if we're doing A's or B's
    var theChar=this.name.charAt(8);
        // check the A's
     if(theChar == "A" && this.checked && !Achecked){
            Achecked = true;    
        }

    });
    if(Achecked){
        // set the input to A
        $("#type").val("A");
        // check _all_ a's are checked
        var thisName;
        var thisChecked = false;

        $(":radio").each(function(){
            var theChar=this.name.charAt(8);
            var checked = this.checked;
            if (theChar == "A"){
            if (this.name == thisName && !thisChecked){
                // Yes wasn't checked - is No?
                if(!checked){
                    notOK = true;
                }
            }
            thisChecked = checked;
            thisName = this.name;
        }
    });
    }else{
        // set the input to B
        $("#type").val("B");            
        // check _all_ b's are checked
            var thisName;
            var thisChecked = false;
            $(":radio").each(function(){
                var theChar=this.name.charAt(8);
                var checked = this.checked;
                if (theChar == "B"){
                if (this.name == thisName && !thisChecked){
                    // A wasn't checked - is B?
                    if(!checked){
                        notOK = true;
                    }
                }
                thisChecked = checked;
                thisName = this.name;
            }
        });
    }
    return notOK;
}    
function haveNo(){
    var thisName;
    var notOK = false;
        $(":radio").each(function(){
            var checked = this.checked;
            if (this.name == thisName){
                //Is this checked 
                if(checked){
                    notOK = true;
                    $("#type").val("C");            
                }

        }
        thisName = this.name;
    });

    return notOK;
}

这很好用,但我完全坚持将它扩展到包括C系列。我现在必须检查用户是否没有回答任何A和B,A和C以及B和C问题。我尝试的一切都无法验证。这是我现在使用我的新脚本的地方:

    $(function() {

        $("#editRecord").submit(function(){

        // is anything checked?
        if(!checkEmpty()){
            $("#error").html("Please check something before submitting");
            //alert("nothing Checked");
            return false;
        }
        // Only A or B or C
        if(isAorBorC()){
            $("#error").html("Please complete A or B or C, not both");
            //alert("please complete A or B, not both");
            return false;
        };
        // all A's or all B's or all C's
        if(allAorBorCChecked()){
            $("#error").html("It appears you have not completed all questions");
            //alert("missing data");
            return false;
        };
        if(haveNo()){
            // we're going on, but sending "type = C"
        }
        //alert("all OK");
            return true;
        });
    });


function checkEmpty(){
    var OK = false;
    $(":radio").each(function(){
        if (this.checked){
            OK = true;
        }
    });
    return OK;
}
function isAorBorC(){
    var OK = false;
    var Achecked = false;
    var Bchecked = false;
    var Cchecked = false;
    $(":radio").each(function(){
        var theChar=this.name.charAt(8);
        // if we have an A checked remember it
         if(theChar == "A" && this.checked && !Achecked){
            Achecked = true;    
        }
        if(theChar == "B" && this.checked && !Achecked){
            Bchecked = true;    
        }
        if(theChar == "C" && this.checked && !Achecked){
            Cchecked = true;    
        }
        if(Achecked && theChar == "B" && !Bchecked){
            if(this.checked){
                Bchecked = true;
            }
        }
        if(Achecked && theChar == "C" && !Cchecked){
            if(this.checked){
                Cchecked = true;
            }
        }
        if(Bchecked && theChar == "C" && !Cchecked){
            if(this.checked){
                Cchecked = true;
            }
        }
        if (Achecked && Bchecked){
            OK = true;
        }
        if (Achecked && CBchecked){
            OK = true;
        }
        if (Bchecked && Cchecked){
            OK = true;
        }
    });
    return OK;
} 
function allAorBorCChecked(){
    var notOK = false;
    var Achecked = false;
    $(":radio").each(function(){
        // skip through to see if we're doing A's or B's
    var theChar=this.name.charAt(8);
        // check the A's
     if(theChar == "A" && this.checked && !Achecked){
            Achecked = true;    
        }

    });
    if(Achecked){
        // set the input to A
        $("#type").val("A");
        // check _all_ a's are checked
        var thisName;
        var thisChecked = false;

        $(":radio").each(function(){
            var theChar=this.name.charAt(8);
            var checked = this.checked;
            if (theChar == "A"){
            if (this.name == thisName && !thisChecked){
                // Yes wasn't checked - is No?
                if(!checked){
                    notOK = true;
                }
            }
            thisChecked = checked;
            thisName = this.name;
        }
    });
    }elseif{
    // set the input to B
        $("#type").val("B");            
        // check _all_ b's are checked
            var thisName;
            var thisChecked = false;
            $(":radio").each(function(){
                var theChar=this.name.charAt(8);
                var checked = this.checked;
                if (theChar == "B"){
                if (this.name == thisName && !thisChecked){
                    // A wasn't checked - is B?
                    if(!checked){
                        notOK = true;
                    }
                }
                thisChecked = checked;
                thisName = this.name;
            }
        });
    }
    return notOK;
}   

    }else{
        // set the input to C
        $("#type").val("C");            
        // check _all_ c's are checked
            var thisName;
            var thisChecked = false;
            $(":radio").each(function(){
                var theChar=this.name.charAt(8);
                var checked = this.checked;
                if (theChar == "C"){
                if (this.name == thisName && !thisChecked){
                    // A wasn't checked - is B?
                    if(!checked){
                        notOK = true;
                    }
                }
                thisChecked = checked;
                thisName = this.name;
            }
        });
    }
    return notOK;
}   
function haveNo(){
    var thisName;
    var notOK = false;
        $(":radio").each(function(){
            var checked = this.checked;
            if (this.name == thisName){
                //Is this checked 
                if(checked){
                    notOK = true;
                    $("#type").val("C");            
                }

        }
        thisName = this.name;
    });

    return notOK;
}

任何人都能看到我做错了什么?

3 个答案:

答案 0 :(得分:2)

为了大大简化您的任务,我建议创建一个单个函数来回答,对于给定的组:a)是否检查了任何内容; b)是否所有东西都经过检查。类似的东西:

function isAnyAllChecked(group) {
    var any = false;
    var all = true;
    $(":radio").each(function(){
        var theChar=this.name.charAt(8);
        if(theChar == group && this.checked){
            any = true;
        }
        if(theChar == group && !this.checked){
            all = false;
        }
    });
    return { any:any, all:all };
}

现在你的其他功能可以简单地重写为:

function isAorBorC() {
    return (isAnyAllChecked("A").any ? 1 : 0) +
           (isAnyAllChecked("B").any ? 1 : 0) +
           (isAnyAllChecked("C").any ? 1 : 0) !== 1;
}

function allAorBorCChecked() {
    var group = isAnyAllChecked("A").any ? "A" :
                isAnyAllChecked("B").any ? "B" :
                isAnyAllChecked("C").any ? "C" :
                undefined;
    if ( group ) {
        $("#type").val(group);
        return !isAnyAllChecked(group).all;
    }
    else
        return true;
}

注意:

  1. 您可以重复使用isAnyAllChecked的返回值来提高效率;我没有在上面的代码中这样做,以保持方法接口不变。

  2. 可以<{em> typecast boolean int(隐式或明确地)而不是any ? 1 : 0,但恕我直言更清楚。

  3. 您也可以将您的解决方案推广到任意数量的组,使用数组和函数,如mapfilter等,但是对于少数你不需要的团体。

答案 1 :(得分:2)

首先,我认为最好的可用性是通过使表单更容易出错来使表单更易于使用。如果您使用的是javascript&amp; jQuery,你也可以设置它,以便用户必须选择一个部分才能选择其中的任何项目。您可以轻松支持显示所有问题的要求,但是当计算机可以非常容易地阻止此操作时,允许用户执行不必要的工作(例如错误地填写多个部分)对用户是不利的。

如果你想看看它的样子,请发表评论,我会为你做点什么。

与此同时,按照您当前的设计,这里是a fiddle demonstrating one possible technique。它适用于任意数量的部分。

请查看完整列表的代码,但这里是执行繁重验证的脚本。

function validate(ev) {
    var sectionsTouched = $('ol').has(':checked'),
       inputs = {},
       errorMessage = '';

    if (sectionsTouched.length === 0) {
        errorMessage = 'Please check something before submitting.';
    } else if (sectionsTouched.length > 1) {
        errorMessage = 'Please complete only one of sections ' + namesCommaDelimited(seriesNames(), 'or') + '.';
    } else {
        sectionsTouched.find('input').each(function(i, e) {
            var me = $(e), name = me.attr('name');
            inputs[name] = !!inputs[name] || me.is(':checked');
        });
        $.each(inputs, function(k, v) {
            if (!v) {
                errorMessage = 'Please complete all questions in your selected section.';
            }
            return v;
        });            
    }
    if (errorMessage !== '') {
        $('#error').html(errorMessage);
        ev.preventDefault();
        return false;
    }
    return true;
}

基本逻辑:如果没有任何部分有选中的项目,则显示相应的消息。如果多个部分有一个选中的项目,则有太多部分有答案。如果只有一个部分有答案,则循环输入并收集那些检查相应控件名称的列表。如果存在任何没有检查的名称,则取消选中某个控制组,并显示相应的消息。

我不得不采取一些自由来构建一个足以满足要求的表格,以便进行适当的演示。这是它的样子:

My demonstration fiddle

我希望这有帮助!

P.S。为了完整起见,我想提一下几种风格的考虑因素:

  • 当您发现自己重复代码时,请尝试抽象重复 - 创建函数或声明变量。例如,不是多次执行$('#error').html(),而是设置一个值,然后只执行一次html设置。
  • 尝试编写不会秘密依赖于文档结构的代码,例如表单字段名称采用特定格式(在某个位置具有特定字符)。你的javascript在很大程度上取决于返回'A'或'B'的charAt(8)函数,这会让它变得脆弱 - 如果其他人(甚至你未来的自己)意外地破坏了控制名称会怎么样?突然,javascript会破坏,两者之间的联系并不明显。您可以对其进行编码,这样您甚至不需要知道哪个部分是哪个部分,只要您有一些可以指示每个部分的选择器。使用类名是可以的,因为javascript中的类名显然必须匹配html中的类名。

答案 2 :(得分:0)

首先,我认为最好的方法是为每个部分提供1个表单,并自行提交。您只验证该表单是否得到了所有答案,就是这样,剩下的就被丢弃了。

<form id="formA">
<input ...

<button type="submit">Submit with A Answers</button>
</form>
<form id="formB">
<input ...

<button type="submit">Submit with B Answers</button>
</form>

等。

但是,如果有理由说明你为什么这样做,那么无论你有多少部分,a,b,c,d,e等等,这里都是如何使它成功的小提琴......

  

http://jsfiddle.net/cUfY4/

还有一件事:有几种方法可以解决这个问题。 建议的Javascript是:

$('form').submit(function( e ){
    e.preventDefault();
    var globalAnswers = 0;
    var globalComplete = false;
    $('.section').each(function() {
        var $this = $(this), sectionHasAnswers = false, sectionComplete = true;
        $this.find('input[type="radio"]').each(function() {
            var inputName = $(this).attr('name');
            if ($('input[name="' + inputName + '"]').is(':checked')) {
                sectionHasAnswers = true;
            } else {
                sectionComplete = false;
            }
        });
        if (sectionComplete && !globalComplete) {
            globalAnswers++
            globalComplete = true;
        } else {
            if (sectionHasAnswers) {globalAnswers++};
        }
    });

        if (globalAnswers == 1 && globalComplete) {
            // EVERYTHING OK! SUBMIT FORM!
        } else {
            // ERRORS use globalAnswers and globalComplete for exact problem
        }
});