jQueryvalidation – 要求填写组中至less有一个字段

我使用优秀的jQuery validation插件来validation一些表单。 在一种forms中,我需要确保用户至less填写一组字段中的一个。 我认为我有一个很好的解决scheme,并希望分享它。 请build议您可以想到的任何改进。

find没有内置的方式来做到这一点,我search,发现丽贝卡·墨菲的自定义validation方法 ,这是非常有益的。

我通过三种方式改进了这一点:

  1. 让你传入一组字段的select器
  2. 为了让你指定有多less组必须被填充进行validation才能通过
  3. 显示组中的所有input作为通过validation,只要其中一个通过validation。 (见尼克·克拉弗最后大喊)

所以你可以说“至less要匹配select器Y的Xinput必须被填充”。

最终的结果是,像这样的标记:

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

Item#3假设你在成功validation的时候添加一个.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.")); 

万岁!

喊出来

现在对于这个大喊 – 原来,我的代码只是盲目地将错误消息隐藏在其他匹配字段上,而不是重新validation它们,这意味着如果还有其他问题(比如“只允许input数字,而且input了字母”) ,直到用户尝试提交时才隐藏起来。 这是因为我不知道如何避免上面评论中提到的反馈循环。 我知道一定有办法,所以我问了一个问题 , Nick Craver给我开了个礼 。 谢谢,尼克!

问题解决了

这本来是一个“让我分享一下,看看有没有人可以提出改进”的问题。 尽pipe我仍然欢迎反馈意见,但我认为这一点非常完整。 (它可能会更短,但我希望它很容易阅读,不一定简洁。)所以只是享受!

更新 – 现在是jQueryvalidation的一部分

这是正式添加到 2012年4月3日jQueryvalidation 。

这是Nathan的一个很好的解决scheme。 非常感谢。

这是一种使上述代码有效的方法,以防有人遇到麻烦,就像我一样:

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

好的解决scheme 但是,我有其他所需的规则不起作用的问题。 对表单执行.valid()修复了这个问题。

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

谢谢肖恩。 这就解决了我用代码忽略了其他规则的问题。

我也做了一些改变,以便“请填写至less1个字段..”信息显示在一个单独的div而不是在每个字段之后。

放在窗体validation脚本

 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;(!)")); 

我已经提交了一个不受当前版本问题影响的修补程序 (其中“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.")); 

在PHP中需要用$来启动一个variables名,但是在Javascript中很奇怪(恕我直言)。 此外,我相信你把它称为“$模块”两次和“模块”一次,对吗? 看来这个代码不应该工作。

另外,我不确定这是否是正常的jQuery插件语法,但是我可能会在addMethod调用之上添加注释,解释您完成的任务。 即使使用上面的文本描述,也很难跟踪代码,因为我不熟悉字段集:fill,value,element或selector是指什么。 也许大多数人对于熟悉Validate插件的人来说是显而易见的,所以请使用关于什么是正确的解释的判断。

也许你可以打出几个代码来自我logging代码; 喜欢,

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

(假设我明白了你的代码块的含义:))

我不完全确定“模块”是什么意思,实际上 – 有一个更具体的名称,你可以给这个variables?

好的代码,总体来说!

因为我正在处理的表单有几个像这些分组input的克隆区域,所以我将一个额外的parameter passing给了require_from_group构造函数,正好改变了addMethod函数的一行:

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

这样一个select器,ID或元素名称可以传递一次:

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

并且validation器将会限制validation元素只在每个字段集中包含该类的元素,而不是尝试统计表单中的所有.reqgrp分类元素。

这里是我对Rocket Hazmat的回答的解答,试图解决还需要validation的其他定义字段的问题,但在成功填写一个字段时将所有字段标记为有效。

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

现在唯一剩下的问题就是边界情况,其中的字段是空的,然后填充,然后再次清空…在这种情况下,错误将被应用于单个字段而不是组。 但是,这似乎不太可能发生在任何频率上,并且在技术上仍然在这种情况下起作用。

我与其他规则没有被检查与此有关的问题,所以我改变了:

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

谢谢,Nathan。 你救了我一吨的时间。

但是,我必须注意到,这个规则是不准备jQuery.noConflict()。 所以,我们必须用jQueryreplace所有的$来处理,比如var $j = jQuery.noConflict()

我有问题:我将如何使其行为像内置规则? 例如,如果我input电子邮件,消息“请input有效的电子邮件”自动消失,但如果我填写组字段错误信息保留。