jQuery Validate-グループ内の少なくとも1つのフィールドに入力する必要があります


98

いくつかのフォームを検証するために、優れたjQuery Validateプラグインを使用しています。1つのフォームで、ユーザーがフィールドのグループの少なくとも1つに入力することを確認する必要があります。私はかなり良い解決策を持っていると思い、それを共有したいと思いました。 考えられる改善点があれば提案してください。

これを行うための組み込みの方法が見つからなかったので、レベッカマーフィーのカスタム検証メソッドを検索して見つけました。これは非常に役に立ちました。

私はこれを3つの方法で改善しました:

  1. フィールドのグループのセレクターを渡すには
  2. 検証に合格するために入力する必要があるグループの数を指定するには
  3. それらの1つが検証に合格するとすぐに、グループ内のすべての入力を検証に合格すると表示する。(最後にNick Craverへの叫びを参照してください。)

したがって、「セレクターYに一致するX入力が少なくとも入力されている必要がありますと言うことができます

最終結果は、次のようなマークアップです。

<input class="productinfo" name="partnumber">
<input class="productinfo" name="description">

...このようなルールのグループです:

// Both these inputs input will validate if 
// at least 1 input with class 'productinfo' is filled
partnumber: {
   require_from_group: [1,".productinfo"]
  }
description: {
   require_from_group: [1,".productinfo"]
}

項目#3は、.checked検証が成功したときにエラーメッセージにのクラスを追加することを前提としています。ここで示すように、これは次のように行うことができます

success: function(label) {  
        label.html(" ").addClass("checked"); 
}

上記のデモのように、CSSを使用してそれぞれspan.errorにX画像を背景として指定します。ただし、クラスがなければ.checked、チェックマーク画像を取得します。

これまでの私のコードは次のとおりです。

jQuery.validator.addMethod("require_from_group", function(value, element, options) {
    var numberRequired = options[0];
    var selector = options[1];
    //Look for our selector within the parent form
    var validOrNot = $(selector, element.form).filter(function() {
         // Each field is kept if it has a value
         return $(this).val();
         // Set to true if there are enough, else to false
      }).length >= numberRequired;

    // The elegent part - this element needs to check the others that match the
    // selector, but we don't want to set off a feedback loop where each element
    // has to check each other element. It would be like:
    // Element 1: "I might be valid if you're valid. Are you?"
    // Element 2: "Let's see. I might be valid if YOU'RE valid. Are you?"
    // Element 1: "Let's see. I might be valid if YOU'RE valid. Are you?"
    // ...etc, until we get a "too much recursion" error.
    //
    // So instead we
    //  1) Flag all matching elements as 'currently being validated'
    //  using jQuery's .data()
    //  2) Re-run validation on each of them. Since the others are now
    //     flagged as being in the process, they will skip this section,
    //     and therefore won't turn around and validate everything else
    //  3) Once that's done, we remove the 'currently being validated' flag
    //     from all the elements
    if(!$(element).data('being_validated')) {
    var fields = $(selector, element.form);
    fields.data('being_validated', true);
    // .valid() means "validate using all applicable rules" (which 
    // includes this one)
    fields.valid();
    fields.data('being_validated', false);
    }
    return validOrNot;
    // {0} below is the 0th item in the options field
    }, jQuery.format("Please fill out at least {0} of these fields."));

やったー!

大声で叫ぶ

今、その叫び声のために-元々、私のコードは、他の一致するフィールドのエラーメッセージを再検証するのではなく、盲目的に隠しました。 、ユーザーが送信しようとするまで非表示になります。これは、上記のコメントに記載されているフィードバックループを回避する方法がわからなかったためです。私は方法があるはずだと知っていたので、私は質問をしました、そしてニック・クレイバーは私に啓発しました。ありがとう、ニック!

解決した質問

これはもともと「これを共有して、誰かが改善を提案できるかどうかを確認してください」という種類の質問でした。私はまだフィードバックを歓迎しますが、現時点ではかなり完成していると思います。(短くすることもできますが、読みやすく、必ずしも簡潔ではないようにしたいと思います。)だから楽しんでください!

更新-jQuery検証の一部になりました

これは、2012年4月3日にjQuery Validation正式に追加されました。


また、密接に関連するルールを参照してください- 「それらの少なくともXこれらのフィールド、または塗りつぶしをスキップどちらか」 - stackoverflow.com/questions/1888976/...
ネイサンロング

なぜ1つの任意の入力が他の入力が入力されているかどうかをチェックする責任があるのですか?これは意味がありません。おそらく、関連する要素に少しマークアップを含めることができますか?
モントリオール主義者、

@dalbaeb-例を少し明確にしました。1つの任意の入力が他の入力をチェックする責任があるということではありません。グループ内の各入力が他のすべてをチェックする責任があるということです。
Nathan Long、

それが私の考えです、ありがとう
モントリオール主義者、

3
おかげで、これは私にとってはうまくいきますが、フォームの他の必須フィールドは、チェック後にフォーカスを取得して失うまで、応答しなくなります。(誰かがこれを他の質問の回答として追加しましたが、回答ではないため、フラグを立てる必要がありました)。
mydoghasworms '05

回答:


21

それはネイサンの優れたソリューションです。どうもありがとう。

私がしたように誰かがそれを統合するのに問題に遭遇した場合に、上記のコードを機能させる方法は次のとおりです:

additional-methods.jsファイル内のコード:

jQuery.validator.addMethod("require_from_group", function(value, element, options) {
...// Nathan's code without any changes
}, jQuery.format("Please fill out at least {0} of these fields."));

// "filone" is the class we will use for the input elements at this example
jQuery.validator.addClassRules("fillone", {
    require_from_group: [1,".fillone"]
});

htmlファイル内のコード:

<input id="field1" class="fillone" type="text" value="" name="field1" />
<input id="field2" class="fillone" type="text" value="" name="field2" />
<input id="field3" class="fillone" type="text" value="" name="field3" />
<input id="field4" class="fillone" type="text" value="" name="field4" />

additional-methods.jsファイルを含めることを忘れないでください!


お役に立ててうれしいです。情報の欠けに感謝します。ただし、addClassRulesメソッドを実行する代わりに、個々のフォームごとに規則の配列を使用することを好みます。このページ(jquery.bassistance.de/validate/demo/milk)に移動して[このページで使用されているスクリプトを表示]をクリックすると、例が表示されます。さらに1歩進んで、 "rules"と呼ばれる配列を宣言し、次に個別にvar validator = $( '#formtovalidate')。validate(rules);で使用します。
ネイサンロング

別の考え:ここで示す「fillone」クラスは問題がある可能性があります。同じフォームで、少なくとも1つの部品番号と少なくとも1つの連絡先名が必要な場合はどうなりますか?ルールでは、少なくとも1つの部品番号がある限り、連絡先名を0にすることができます。私はそれがより良いように設定されたルールにだと思うrequire_from_group: [1,".partnumber"]し、...[1,".contactname"]あなたが正しいことを確認していることを確認します。
Nathan Long

6

素晴らしい解決策。しかし、他の必要なルールが機能しないという問題がありました。フォームに対して.valid()を実行すると、この問題が修正されました。

if(!$(element).data('being_validated')) {
  var fields = $(selector, element.form);
  fields.data('being_validated', true); 
  $(element.form).valid();
  fields.data('being_validated', false);
}

1
ショーンのおかげで、私もこの問題を抱えていました。ただし、このソリューションには1つの問題があります。ユーザーが初めてフォームにアクセスしたとき-最初のrequire-from-groupフィールドに入力するとすぐに、他のすべてのフォームフィールドが検証され、不良としてマークされます。これを解決する方法は、フラグを設定したバリデーターのインスタンスを作成する前にform.submit()ハンドラーを追加することでしたvalidator.formSubmit = true。require-from-groupメソッドで、そのフラグを確認します。そこにあれば私は$(element.form).valid();そうし、そうでなければ私はしますfields.valid();
Christof

誰かが実際にここで起こっていることを説明できますか?私はかなり似たルールを持っていますが、うまくいきましたが、再検証の問題には対処していません(グループ内の他のフィールドはまだ無効とマークされています)。しかし、私は現在、フォームが無効であっても送信することを経験しています。グループ化されたフィールドが有効な場合は、submithandlerに入らず、無効な場合はinvalidHandlerに入りますが、送信します。これは検証プラグインのかなり深刻なバグだと思いますか?ルールが有効であることを返すと、そのルールにのみ適用されます(フィールド全体でさえ適用されない)ので、無効なフォームが送信されるのはなぜですか?
Adam

私はさらに調査しましたが、それはグループの前の分野であり、適切に検証されていません。私は(私はdiscoiveredている部分的な回避策で)別々の質問としてこれを求めている:stackoverflow.com/questions/12690898/...
アダム

4

ショーン、ありがとう。これにより、コードが他のルールを無視していた問題が修正されました。

また、「少なくとも1つのフィールドに入力してください...」というメッセージがすべてのフィールドの最後に表示されるのではなく、別のdivに表示されるようにいくつかの変更を加えました。

フォーム検証スクリプトに入れる

showErrors: function(errorMap, errorList){
            $("#form_error").html("Please fill out at least 1 field before submitting.");
            this.defaultShowErrors();
        },

これをページのどこかに追加します

<div class="error" id="form_error"></div>

require_from_groupメソッドに追加しますaddMethod関数

 if(validOrNot){
    $("#form_error").hide();
}else{
    $("#form_error").show();
}
......
}, jQuery.format(" &nbsp;(!)"));

4

現在のバージョンで発生する問題の影響を受けないパッチを提出しました(「必須」オプションが他のフィールドで適切に機能しなくなるため、現在のバージョンでの問題についての議論はgithubにあります。

http://jsfiddle.net/f887W/10/の

jQuery.validator.addMethod("require_from_group", function (value, element, options) {
var validator = this;
var minRequired = options[0];
var selector = options[1];
var validOrNot = jQuery(selector, element.form).filter(function () {
    return validator.elementValue(this);
}).length >= minRequired;

// remove all events in namespace require_from_group
jQuery(selector, element.form).off('.require_from_group');

//add the required events to trigger revalidation if setting is enabled in the validator
if (this.settings.onkeyup) {
    jQuery(selector, element.form).on({
        'keyup.require_from_group': function (e) {
            jQuery(selector, element.form).valid();
        }
    });
}

if (this.settings.onfocusin) {
    jQuery(selector, element.form).on({
        'focusin.require_from_group': function (e) {
            jQuery(selector, element.form).valid();
        }
    });
}

if (this.settings.click) {
    jQuery(selector, element.form).on({
        'click.require_from_group': function (e) {
            jQuery(selector, element.form).valid();
        }
    });
}

if (this.settings.onfocusout) {
    jQuery(selector, element.form).on({
        'focusout.require_from_group': function (e) {
            jQuery(selector, element.form).valid();
        }
    });
}

return validOrNot;
}, jQuery.format("Please fill at least {0} of these fields."));

3

PHPでは変数名を$で始める必要がありますが、JavaScriptではかなり奇妙です(IMHO)。また、「$ module」を2回、「module」を1回と呼んでいると思いますよね?このコードは機能しないようです。

また、それが通常のjQueryプラグインの構文であるかどうかはわかりませんが、addMethod呼び出しの上に、達成したことを説明するコメントを追加する場合があります。上記のテキストの説明を使用しても、fieldset、:filled、value、element、selectorが何を参照しているのかよくわからないため、コードを理解するのは困難です。おそらくこれのほとんどは、Validateプラグインに精通している人には明らかであるため、適切な量の説明について判断してください。

おそらく、いくつかの変数を分割して、コードを自己文書化することができます。お気に入り、

var atLeastOneFilled = module.find(...).length > 0;
if (atLeastOneFilled) {
  var stillMarkedWithErrors = module.find(...).next(...).not(...);
  stillMarkedWithErrors.text("").addClass(...)

(私があなたのコードのこれらのチャンクの意味を理解したと仮定します!:))

「モジュール」が何を意味するのか正確にはわかりませんが、実際には-この変数にもっと具体的な名前を付けることはできますか?

全体的に素晴らしいコードです!


提案をありがとう-私は変数名を明確にし、コードを少し読みやすくするために分解しました。
ネイサンロング

2

私が取り組んでいるフォームには、これらのようなグループ化された入力を持つ複数のクローン領域があるため、require_from_groupコンストラクターに追加の引数を渡して、addMethod関数の1行だけを変更しました。

var commonParent = $(element).parents(options[2]);

このようにして、セレクタ、ID、または要素名を1回渡すことができます。

jQuery.validator.addClassRules("reqgrp", {require_from_group: [1, ".reqgrp", 'fieldset']});

バリデーターは、フォーム内のすべての.reqgrpクラス要素をカウントするのではなく、各フィールドセット内でのみ、そのクラスを持つ要素に検証を制限します。


2

これはRocket Hazmatの答えの私の亀裂です。検証が必要な他の定義済みフィールドの問題を解決しようとしていますが、フィールドの入力が成功するとすべてのフィールドを有効としてマークします。

jQuery.validator.addMethod("require_from_group", function(value, element, options){
    var numberRequired = options[0],
    selector = options[1],
    $fields = $(selector, element.form),
    validOrNot = $fields.filter(function() {
        return $(this).val();
    }).length >= numberRequired,
    validator = this;
    if(!$(element).data('being_validated')) {
        $fields.data('being_validated', true).each(function(){
            validator.valid(this);
        }).data('being_validated', false);
    }
    if (validOrNot) {
    $(selector).each(function() {
            $(this).removeClass('error');
            $('label.error[for='+$(this).attr('id')+']').remove();
        });
    }
    return validOrNot;
}, jQuery.format("Please fill out at least {0} of these fields."));

これで残っている唯一の問題は、フィールドが空になり、次に入力され、再び空になるというエッジケースです。この場合、エラーはグループではなく単一のフィールドに適用されます。しかし、それはどの周波数でも起こりそうにないようで、その場合でも技術的には機能します。


このメソッド/ルールは2012
。– Sparky

Rocket Hazmatと同じ問題がありますが、現在バリデーターに同梱されています。フィールドの1つのグループが検証されますが、他のメソッドを使用する他のフィールドは検証されません。この答えはその問題を解決する試みです。より良い解決策がある場合はお知らせください。
squarecandy 2013

開発者が問題を完全に修正するまでは、混乱を招くのではなく、一時的な解決策をここで承認することをお勧めします: github.com/jzaefferer/jquery-validation/issues/412
Sparky

1

これに関連して他のルールがチェックされないという問題があったため、変更しました:

fields.valid();

これに:

var validator = this;
fields.each(function(){
   validator.valid(this);
});

私もいくつかの(個人的な)改善を行いました。これは私が使用しているバージョンです。

jQuery.validator.addMethod("require_from_group", function(value, element, options){
    var numberRequired = options[0],
    selector = options[1],
    $fields = $(selector, element.form),
    validOrNot = $fields.filter(function() {
        return $(this).val();
    }).length >= numberRequired,
    validator = this;
    if(!$(element).data('being_validated')) {
        $fields.data('being_validated', true).each(function(){
            validator.valid(this);
        }).data('being_validated', false);
    }
    return validOrNot;
}, jQuery.format("Please fill out at least {0} of these fields."));

他のフィールドを再度検証するように機能しますが、グループのすべてのフィールドが無効としてマークされており、1つ入力すると、その1つだけが検証されます。少なくとも私にとっては?
クリストフ

@Chris-これに基づいて構築され、これに対処する私の新しい答えを参照してください。
squarecandy 2013

0

ありがとう、ネイサン。あなたは私にたくさんの時間を節約しました。

ただし、このルールではjQuery.noConflict()の準備が整っていないことに注意する必要があります。したがって、たとえば、すべての$をjQueryで置き換える必要があります。var $j = jQuery.noConflict()

そして、私は質問があります:組み込みのルールのように動作させるにはどうすればよいですか?たとえば、電子メールを入力すると、「有効な電子メールを入力してください」というメッセージは自動的に消えますが、グループフィールドの1つに入力すると、エラーメッセージが残ります。


あなたは正しい-私は紛争のない状況を考慮しなかった。将来的には更新する可能性がありますが、必要に応じて簡単に検索して置換できます。2番目の質問については、同じ問題は発生しません。簡単なテストで、グループの1つのフィールドが必要な場合、何かを入力するとすぐに、グループ全体がそのルールに合格します。複数が必要な場合、最後に必要なものが満たされ、フォーカスが失われるとすぐに、グループ全体が合格します。それが見えますか?
ネイサンロング

なんらかの理由でマークアップが台無しになり、修正に成功しませんでした
Rinat

Rinat-問題を単純化して絞り込むことができますか?競合のない変更を必要としない単純なフォームでコードを使用してみてください。テストできる最も単純なフォームを実行し、それを最初に機能させます。
ネイサンロング
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.