3

もともとは一連の質問(A1からA5およびB1からB3)であった単純なHTMLフォームがあり、次のようなはい/いいえのラジオボタンがあります。

<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. を行う代わりに(暗黙的または明示的に)に型キャストすることもでき ますが、その方法の方が明確です。booleanintany ? 1 : 0

  3. 配列や関数などを使用して、ソリューションを任意の数のグループに一般化することもできますが、少数のグループの場合、それは実際には必要ありません。mapfilter

于 2012-11-26T03:49:04.523 に答える
2

まず第一に、間違いを起こしにくくすることで、フォームを使いやすくすることが一番の使いやすさだと思います。javascriptとjQueryを使用している場合は、ユーザーがセクション内のアイテムを選択する前にセクションを選択する必要があるように設定することもできます。すべての質問を表示するという要件を簡単にサポートできますが、コンピューターがこれを非常に簡単に防ぐことができる場合に、ユーザーが不必要な作業(複数のセクションに誤って入力するなど)を実行できるようにすることはユーザーにとって不利益です。

それがどのように見えるかを知りたい場合は、コメントしてください。私があなたのために何かを作り上げます。

それまでの間、現在のデザインに沿って、1つの可能なテクニックを示すフィドルを示します。これは、任意の数のセクションで機能します。

完全なリストについては、そのコードを参照してください。ただし、検証を大幅に強化するスクリプトは次のとおりです。

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

基本ロジック:チェック項目のあるセクションがない場合は、適切なメッセージを表示します。複数のセクションにチェック項目がある場合、答えが多すぎるセクションがあります。ちょうど1つのセクションに回答がある場合は、入力をループして、対応するコントロール名をチェックしているセクションのリストを収集します。チェックされていない名前が存在する場合、一部のコントロールグループはチェックされないままになり、適切なメッセージが表示されます。

適切なデモンストレーションを行うために、要件に十分に適合するフォームを作成するために、私はいくつかの自由をとらなければなりませんでした。これがどのように見えるかです:

私のデモンストレーションフィドル

これがお役に立てば幸いです。

PS完全を期すために、いくつかのスタイルの考慮事項について説明します。

  • コードを繰り返していることに気付いたら、繰り返しを抽象化してみてください。関数を作成するか、変数を宣言してください。たとえば、$('#error').html()複数回行うのではなく、値を設定してからhtml設定を1回だけ行います。
  • フォームフィールド名が特定の形式である(特定の文字が位置にある)など、ドキュメントの構造に密かに依存しないコードを記述してみてください。あなたのJavaScriptは、「A」または「B」を返す関数に大きく依存しているcharAt(8)ため、脆弱になります。他の誰か(または将来の自分)が誤ってコントロール名を壊してしまった場合はどうなりますか?突然javascriptが壊れ、2つの間のリンクが明確になりません。個々のセクションを示すことができるセレクターがある限り、どのセクションがどのセクションであるかを知る必要がないようにコーディングできます。javascriptのクラス名は明らかにhtmlのクラス名と一致する必要があるため、クラス名を使用しても問題ありません。
于 2012-11-26T07:56:06.887 に答える
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、fなどの数に関係なくそれがどのように機能することができるかについてのフィドルがあります。

http://jsfiddle.net/cUfY4/

もう1つ、この問題を解決するにはいくつかの方法があります。提案されている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 に答える