简体   繁体   English

jQuery Validate - 要求填充组中的至少一个字段

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

I'm using the excellent jQuery Validate Plugin to validate some forms. 我正在使用优秀的jQuery Validate插件来验证某些表单。 On one form, I need to ensure that the user fills in at least one of a group of fields. 在一种形式上,我需要确保用户填写一组字段中的至少一个。 I think I've got a pretty good solution, and wanted to share it. 我想我有一个很好的解决方案,想分享它。 Please suggest any improvements you can think of. 请提出您可以想到的任何改进建议。

Finding no built-in way to do this, I searched and found Rebecca Murphey's custom validation method , which was very helpful. 找不到这样做的内置方法,我搜索并找到了Rebecca Murphey的自定义验证方法 ,这非常有用。

I improved this in three ways: 我通过三种方式改进了这个:

  1. To let you pass in a selector for the group of fields 让您传入一组字段的选择器
  2. To let you specify how many of that group must be filled for validation to pass 允许您指定必须填充该组的数量才能通过验证
  3. To show all inputs in the group as passing validation as soon as one of them passes validation. 一旦其中一个输入通过验证,就将组中的所有输入显示为通过验证。 (See shout-out to Nick Craver at end.) (见呼喊出到尼克Craver在结束)。

So you can say "at least X inputs that match selector Y must be filled." 所以你可以说“至少必须填充匹配选择器Y的X输入。”

The end result, with markup like this: 最终结果,标记如下:

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

...is a group of rules like this: ......是一组这样的规则:

// 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"]
}

Item #3 assumes that you're adding a class of .checked to your error messages upon successful validation. 项目#3假定您在成功验证.checked错误消息添加到.checked类中。 You can do this as follows, as demonstrated here . 你可以这样做如下, 这里展示

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

As in the demo linked above, I use CSS to give each span.error an X image as its background, unless it has the class .checked , in which case it gets a check mark image. 与上面链接的演示一样,我使用CSS为每个span.error一个X图像作为其背景,除非它有类.checked ,在这种情况下它会得到一个复选标记图像。

Here's my code so far: 到目前为止,这是我的代码:

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

Hooray! 万岁!

Shout out 喊出来

Now for that shout-out - originally, my code just blindly hid the error messages on the other matching fields instead of re-validating them, which meant that if there was another problem (like 'only numbers are allowed and you entered letters'), it got hidden until the user tried to submit. 现在为了那个喊叫 - 最初,我的代码只是盲目地隐藏其他匹配字段上的错误消息而不是重新验证它们,这意味着如果还有另一个问题(比如'只允许数字而你输入字母') ,它一直隐藏,直到用户试图提交。 This was because I didn't know how to avoid the feedback loop mentioned in the comments above. 这是因为我不知道如何避免上述评论中提到的反馈循环。 I knew there must be a way, so I asked a question , and Nick Craver enlightened me. 我知道必须有办法,所以我问了一个问题尼克克拉弗开悟了我。 Thanks, Nick! 谢谢,尼克!

Question Solved 问题解决了

This was originally a "let me share this and see if anybody can suggest improvements" kind of question. 这最初是“让我分享这个,看看是否有人可以提出改进”的问题。 While I'd still welcome feedback, I think it's pretty complete at this point. 虽然我仍然欢迎反馈,但我认为这一点非常完整。 (It could be shorter, but I want it to be easy to read and not necessarily concise.) So just enjoy! (它可能更短,但我希望它易于阅读,而不一定简洁。)所以只是享受!

Update - now part of jQuery Validation 更新 - 现在是jQuery验证的一部分

This was officially added to jQuery Validation on 4/3/2012. 这已于2012年4月3日正式添加到jQuery验证中。

That's an excellent solution Nathan. 这是一个出色的解决方案内森。 Thanks a lot. 非常感谢。

Here's a way making the above code work, in case someone runs into trouble integrating it, like I did: 这是使上述代码工作的一种方法,以防有人遇到麻烦整合它,就像我做的那样:

Code inside the additional-methods.js file: 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"]
});

Code inside the html file: 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" />

Don't forget to include additional-methods.js file! 别忘了包含additional-methods.js文件!

Nice solution. 好的解决方案 However, I had the problem of other required rules not working. 但是,我遇到了其他必要规则不起作用的问题。 Executing .valid() against the form fixed this issue for me. 针对表单执行.valid()为我解决了这个问题。

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

I've submitted a patch that doesn't suffer from the issues the current version does (whereby the "required" option stops working properly on other fields, a discussion of the problems with the current version is on github . 我已经提交了一个不受当前版本问题影响的补丁 (其中“required”选项在其他字段上停止正常工作,当前版本的问题讨论在github上

Example at http://jsfiddle.net/f887W/10/ 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."));

Thanks sean. 谢谢肖恩。 That fixed the issue I had with the code ignoring other rules. 这解决了我对代码忽略其他规则的问题。

I also made a few changes so that 'Please fill out at least 1 field ..' message shows in a separate div instead of after all every field. 我还做了一些更改,以便“请填写至少1个字段..”消息显示在一个单独的div中,而不是在所有每个字段之后。

put in form validate script 放入表单验证脚本

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

add this somewhere in the page 在页面的某处添加它

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

add to the require_from_group method addMethod function 添加到require_from_group方法的addMethod函数

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

Starting a variable name with $ is required in PHP, but pretty weird (IMHO) in Javascript. 在PHP中需要使用$启动变量名称,但在Javascript中非常奇怪(恕我直言)。 Also, I believe you refer to it as "$module" twice and "module" once, right? 另外,我相信你把它称为“$ module”两次,“模块”一次,对吧? It seems that this code shouldn't work. 似乎这段代码不起作用。

Also, I'm not sure if it's normal jQuery plugin syntax, but I might add comments above your addMethod call, explaining what you accomplish. 另外,我不确定它是否是正常的jQuery插件语法,但我可能会在addMethod调用之上添加注释,解释你完成了什么。 Even with your text description above, it's hard to follow the code, because I'm not familiar with what fieldset, :filled, value, element, or selector refer to. 即使你上面的文字描述,也很难遵循代码,因为我不熟悉哪个字段集:fill,value,element或selector引用。 Perhaps most of this is obvious to someone familiar with the Validate plugin, so use judgment about what is the right amount of explanation. 也许对于熟悉Validate插件的人来说,大部分内容都是显而易见的,因此请使用判断适当数量的解释。

Perhaps you could break out a few vars to self-document the code; 也许你可以打破几个变量来自我记录代码; like, 喜欢,

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

(assuming I did understand the meaning of these chunks of your code! :) ) (假设我确实理解了这些代码块的含义!:))

I'm not exactly sure what "module" means, actually -- is there a more specific name you could give to this variable? 我不确定“模块”是什么意思,实际上 - 你可以给这个变量一个更具体的名字吗?

Nice code, overall! 好的代码,整体而言!

Here's my crack at Rocket Hazmat's answer, trying to solve the issue of other defined fields also needing to be validated, but marking all fields as valid on successful filling of one. 这是我对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."));

The only remaining issue with this now is the edge case where the field is empty, then filled, then empty again... in which case the error will by applied to the single field not the group. 现在唯一剩下的问题是边缘情况,其中字段为空,然后填充,然后再次为空......在这种情况下,错误将应用于单个字段而不是组。 But that seems so unlikely to happen with any frequency and it still technically works in that case. 但这似乎不太可能以任何频率发生,并且在这种情况下它仍然在技术上有效。

Because the form I'm working on has several cloned regions with grouped inputs like these, I passed an extra argument to the require_from_group constructor, changing exactly one line of your addMethod function: 因为我正在处理的表单有几个带有分组输入的克隆区域,所以我向require_from_group构造函数传递了一个额外的参数,只改变了addMethod函数的一行:

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

and this way a selector, ID or element name can be passed once: 这样一个选择器,ID或元素名称可以传递一次:

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

and the validator will restrict the validation to elements with that class only inside each fieldset, rather than try to count all the .reqgrp classed elements in the form. 验证器将仅在每个字段集内限制验证到具有该类的元素,而不是尝试计算表单中的所有.reqgrp分类元素。

I was having problems with other rules not being checked in conjunction with this, so I changed: 其他规则没有与此一起检查时遇到问题,所以我改变了:

fields.valid();

To this: 对此:

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

I also made a few (personal) improvements, and this is the version I'm using: 我还做了一些(个人)改进,这是我正在使用的版本:

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

Thanks, Nathan. 谢谢,内森。 You saved me a ton of time. 你救了我很多时间。

However, i must notice that this rule isn't jQuery.noConflict() ready. 但是,我必须注意到这个规则不是jQuery.noConflict()准备好的。 So, one must replace all $ with jQuery to work with, say, var $j = jQuery.noConflict() 因此,必须使用jQuery替换所有$,例如, var $j = jQuery.noConflict()

And i have question: how would i make it behave like built-in rule? 我有疑问:我如何使其表现得像内置规则? For example, if i enter email, the message "Please enter valid email" disappears automatically but if i fill one of group fields error message stays. 例如,如果我输入电子邮件,则“请输入有效电子邮件”消息会自动消失,但如果我填写其中一个组字段,则会显示错误消息。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM