jQuery Validate-至少需要填充一组字段


98

我正在使用出色的jQuery Validate插件来验证某些表单。在一个表单上,我需要确保用户填写一组字段中的至少一个。我认为我有一个很好的解决方案,并希望与大家分享。 请提出您可以想到的任何改进。

我没有找到任何内置方法来执行此操作,因此搜索并找到了Rebecca Murphey的自定义验证方法,该方法非常有帮助。

我通过三种方式对此进行了改进:

  1. 让您传递一组字段的选择器
  2. 为了让您指定该组中必须填充多少组才能通过验证
  3. 一旦其中一个输入通过验证,就将该组中的所有输入显示为通过验证。(请参阅对尼克·克雷弗大喊大叫。)

因此,您可以说“必须至少填充与选择器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.errorX图像提供背景,除非它具有class .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."));

万岁!

喊出来

现在,大声疾呼-最初,我的代码只是盲目地将错误消息隐藏在其他匹配字段上,而不是重新验证它们,这意味着如果还有另一个问题(例如“只允许输入数字并且您输入了字母”) ,直到用户尝试提交之前它一直被隐藏。这是因为我不知道如何避免上面评论中提到的反馈循环。我知道一定有办法,所以我问了一个问题尼克·克拉弗Nick Craver)启发了我。谢谢,尼克!

问题解决

这最初是“让我分享这一点,看看是否有人可以提出改进建议”这类问题。虽然我仍然欢迎反馈,但是我认为到此为止已经很完整了。(它可能会更短一些,但我希望它易于阅读,但不一定要简洁。)那就尽情享受吧!

更新-现在是jQuery验证的一部分

这已在2012年4月3 日正式添加到jQuery Validation中。


此外,请参阅密切相关的规则- “要么跳过这些字段,或者填充至少其中的X” - stackoverflow.com/questions/1888976/...
内森龙

为什么一个任意输入负责检查是否填充了其他输入?这没有道理。也许您可以在涉及的元素中加上一些标记?
蒙特利尔,

@dalbaeb-我对示例进行了澄清。不是一个任意输入负责检查其他输入;是组中的每个输入都负责检查所有其他输入。
内森·朗

那就是我的想法,非常感谢!
蒙特利尔,

3
谢谢,这对我有用,但是表格中的其他必填字段现在不再响应,除非它们在检查后失去焦点。(有人将此添加为您对其他问题的答案,但必须将其标记出来,因为这不是答案)。
mydoghasworms 2011年

Answers:


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),然后单击“显示此页面上使用的脚本”,您将看到一个示例。我更进一步:我声明了一个名为“ rules”的数组,然后单独使用varvalidator = $('#formtovalidate')。validate(rules);
内森·朗2009年

另一个想法:您在此处显示的“ fillone”类可能有问题。如果在同一表格上您需要至少一个零件号和至少一个联系人姓名怎么办?您的规则将允许0个联系人姓名,只要至少有一个部件号即可。我认为最好设置类似规则require_from_group: [1,".partnumber"]...[1,".contactname"]确保您在验证正确的事情。
内森·朗2009年

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
谢谢肖恩,我也遇到了这个问题。但是,此解决方案存在一个问题,当用户首次进入表单时-一旦他填写了第一个“来自组的需求”字段,所有其他表单字段都将被验证并因此标记为错误。我解决此问题的方法是在创建验证器的实例之前添加form.submit()处理程序,在该实例中设置一个flag validator.formSubmit = true。然后在require-from-group方法中检查该标志;如果在那儿我就做$(element.form).valid();,否则我就做fields.valid();
Christof 2012年

谁能解释这里实际发生了什么?我有一个相当相似的规则,该规则已经起作用,但是其中我们没有解决重新验证问题(组中的其他字段仍标记为无效)。但是现在我遇到了即使无效也要提交的表单。如果分组的字段有效,则不输入submithandler;如果无效,则输入invalidHandler,但无论如何都提交!我会说这是验证插件中一个相当严重的错误?规则返回有效的规则仅适用于该规则(甚至不适用整个字段),那么为什么提交了无效的表单?
亚当

我进行了进一步的调查,该小组之前的领域无法正确验证。我曾作为一个单独的问题问过(我已经解决了部分变通方法):stackoverflow.com/questions/12690898/…–
亚当(Adam

4

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

我还进行了一些更改,以使“请至少填写一个字段..”消息显示在单独的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

我已经提交了一个补丁,该补丁不会受到当前版本的问题的困扰(因此,“ 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."));

3

在PHP中以$开头的变量名是必需的,但是在Javascript中却很奇怪(IMHO)。另外,我相信您将它两次称为“ $ module”,一次称为“ module”,对吗?似乎该代码不起作用。

另外,我不确定这是否是普通的jQuery插件语法,但是我可能会在addMethod调用上方添加注释,以说明完成的操作。即使上面有您的文字描述,也很难遵循该代码,因为我对字段集:filled,value,element或选择器所引用的内容并不熟悉。对于熟悉Validate插件的人来说,大多数可能是显而易见的,因此请对正确的解释量进行判断。

也许您可以分解一些变量来自我编写代码。喜欢,

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

(假设我确实理解了您的代码的这些块的含义!:))

实际上,我不确定“模块”的含义是什么?您可以为这个变量指定更具体的名称吗?

总体来说不错的代码!


感谢您的建议-我已经弄清了变量名并分解了代码,使其更具可读性。
内森·朗

2

因为我正在处理的表单具有几个具有类似这些分组输入的克隆区域,所以我将一个额外的参数传递给了require_from_group构造函数,恰好更改了addMethod函数的一行:

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

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

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在验证程序附带的方法中遇到的问题相同。它会验证一组字段,但不会验证使用其他方法的其他字段。该答案是试图解决该问题的尝试。如果您有更好的解决方案,请告诉我。
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."));

可以使其他字段再次生效,但是现在,当组中的所有字段都标记为无效并且您填写一个字段时,只有那个字段得到了验证。至少对于我来说?
Christof

@Chris-请参阅以此为基础并解决此问题的新答案。
squarecandy13年

0

谢谢,内森。你节省了我很多时间。

但是,我必须注意,此规则尚未准备好jQuery.noConflict()。因此,必须使用jQuery替换所有$,例如,var $j = jQuery.noConflict()

我有一个问题:我如何使它表现为内置规则?例如,如果我输入电子邮件,则消息“请输入有效的电子邮件”会自动消失,但是如果我填写组字段之一,则错误消息仍然存在。


您是对的-我没有考虑无冲突的情​​况。我可能会在将来进行更新,但是如果您愿意,您可以轻松地进行查找和替换。对于第二个问题,我没有看到相同的问题。通过快速测试,如果需要组中的一个字段,则在我键入任何内容后,整个组就会通过该规则。如果需要多个,则一旦最后一个被填满并失去焦点,整个团队就会通过。那是你看到的吗?
内森·朗

嗯,由于某种原因,标记被搞砸了,而我却没有成功修复它
Rinat 2010年

Rinat-您可以简化并缩小问题的范围吗?尝试在不需要noconflict更改的简单表单上使用我的代码。做您可以测试的最简单的形式,然后首先使它起作用。
内森·朗
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.