3

我有一个简单的 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;
}

有人看到我做错了什么吗?

4

3 回答 3

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. 可以 将您的类型转换booleanint(隐式或显式)而不是做any ? 1 : 0,但恕我直言,这种方式更清晰。

  3. 您还可以map使用数组和函数(如等)将您的解决方案推广到任意数量的组,filter但对于您拥有的少数组,这并不是真正需要的。

于 2012-11-26T03:49:04.523 回答
2

首先,我认为最好的可用性是让表单更容易使用,更难出错。如果您使用的是 javascript 和 jQuery,您也可以进行设置,以便用户必须先选择一个部分,然后才能选择其中的任何项目。您可以轻松地支持显示所有问题的要求,但是当计算机可以很容易地阻止这种情况时,允许他们执行不必要的工作(例如错误地填写多个部分)对用户是一种伤害。

如果你想看看它可能是什么样子,请发表评论,我会为你做一些事情。

同时,根据您当前的设计,这里有一个演示一种可能技术的小提琴。它适用于任意数量的部分。

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

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;
}

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

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

我的演示小提琴

我希望这有帮助!

PS为了完整起见,我想提几个风格考虑:

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

首先,我认为最好的方法是每个部分都有一个表格,并有自己的提交。您只需验证该表单是否得到了全部答复,仅此而已,其余的都被丢弃了。

<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>

ETC..

但是以防万一你这样做是有原因的,这里有一个关于它如何使它工作的小提琴,不管你有多少个部分,a、b、c、d、e、f 等。

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
        }
});
于 2012-11-26T05:41:27.193 回答