簡體   English   中英

jQuery Validate - 要求填充組中的至少一個字段

[英]jQuery Validate - require at least one field in a group to be filled

我正在使用優秀的jQuery Validate插件來驗證某些表單。 在一種形式上,我需要確保用戶填寫一組字段中的至少一個。 我想我有一個很好的解決方案,想分享它。 請提出您可以想到的任何改進建議。

找不到這樣做的內置方法,我搜索並找到了Rebecca Murphey的自定義驗證方法 ,這非常有用。

我通過三種方式改進了這個:

  1. 讓您傳入一組字段的選擇器
  2. 允許您指定必須填充該組的數量才能通過驗證
  3. 一旦其中一個輸入通過驗證,就將組中的所有輸入顯示為通過驗證。 (見呼喊出到尼克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錯誤消息添加到.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驗證中。

這是一個出色的解決方案內森。 非常感謝。

這是使上述代碼工作的一種方法,以防有人遇到麻煩整合它,就像我做的那樣:

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文件!

好的解決方案 但是,我遇到了其他必要規則不起作用的問題。 針對表單執行.valid()為我解決了這個問題。

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

我已經提交了一個不受當前版本問題影響的補丁 (其中“required”選項在其他字段上停止正常工作,當前版本的問題討論在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."));

謝謝肖恩。 這解決了我對代碼忽略其他規則的問題。

我還做了一些更改,以便“請填寫至少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;(!)"));

在PHP中需要使用$啟動變量名稱,但在Javascript中非常奇怪(恕我直言)。 另外,我相信你把它稱為“$ module”兩次,“模塊”一次,對吧? 似乎這段代碼不起作用。

另外,我不確定它是否是正常的jQuery插件語法,但我可能會在addMethod調用之上添加注釋,解釋你完成了什么。 即使你上面的文字描述,也很難遵循代碼,因為我不熟悉哪個字段集:fill,value,element或selector引用。 也許對於熟悉Validate插件的人來說,大部分內容都是顯而易見的,因此請使用判斷適當數量的解釋。

也許你可以打破幾個變量來自我記錄代碼; 喜歡,

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

(假設我確實理解了這些代碼塊的含義!:))

我不確定“模塊”是什么意思,實際上 - 你可以給這個變量一個更具體的名字嗎?

好的代碼,整體而言!

這是我對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."));

現在唯一剩下的問題是邊緣情況,其中字段為空,然后填充,然后再次為空......在這種情況下,錯誤將應用於單個字段而不是組。 但這似乎不太可能以任何頻率發生,並且在這種情況下它仍然在技術上有效。

因為我正在處理的表單有幾個帶有分組輸入的克隆區域,所以我向require_from_group構造函數傳遞了一個額外的參數,只改變了addMethod函數的一行:

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

這樣一個選擇器,ID或元素名稱可以傳遞一次:

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

驗證器將僅在每個字段集內限制驗證到具有該類的元素,而不是嘗試計算表單中的所有.reqgrp分類元素。

其他規則沒有與此一起檢查時遇到問題,所以我改變了:

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."));

謝謝,內森。 你救了我很多時間。

但是,我必須注意到這個規則不是jQuery.noConflict()准備好的。 因此,必須使用jQuery替換所有$,例如, var $j = jQuery.noConflict()

我有疑問:我如何使其表現得像內置規則? 例如,如果我輸入電子郵件,則“請輸入有效電子郵件”消息會自動消失,但如果我填寫其中一個組字段,則會顯示錯誤消息。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM