3

我正在制作一个需要填写至少一个字段并且所有输入必须是整数或小数的表格。我正在使用 jquery 的验证插件进行验证。我已经修改了我在这里找到的东西,这似乎部分起到了作用。现在我有:

<SCRIPT>   
jQuery.validator.addMethod("require_from_group", function(value, element, options) {
    var numberRequired = options[0];
    var selector = options[1];
    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;
    if(!$(element).data('being_validated')) {
         var fields = $(selector, element.form);
         fields.data('being_validated', true);
         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."));

$(document).ready(function(){
    var container = $('#errorContainer');
    $("#FORMMM").validate(  {
        rules: {
            groceries: {digits: true,require_from_group: [1,".at_least_one"]},
            gas: {digits: true,require_from_group: [1,".at_least_one"]},
            hotels: {digits: true,require_from_group: [1,".at_least_one"]}

        },
        success: function(label) {  
                label.html(" ").addClass("checked"); 
        },
        errorContainer: container,
            errorLabelContainer: $("ol", container),
            wrapper: 'li',
            meta: "validate"
    });
});
</SCRIPT>

HTML 在下面,在我的实际表单中,有 15 个输入字段,我只是在这里压缩它:

<form action="results.php" target="_blank" id="FORMMM">

    <div style="clear:both">
    <label for="groceries">Groceries</label>
    <div style="float:right">
            $<input name="groceries" type="text" class="at_least_one idleField"></div>
    </div>
    <div style="clear:both">
        <label for="gas">Gas</label>
        <div style="float:right">
            $<input name="gas" type="text" class="at_least_one idleField">
        </div>
    </div>
    <div style="clear:both">
        <label for="hotels">Hotels</label>
        <div style="float:right">
            $<input name="hotels" type="text" class="at_least_one idleField">
        </div>
    </div>
    <div id="button">
        <input name="" type="submit" value="Calculate" class="calc_button" style="cursor:hand">
    </div>
    </form>
<div id="errorContainer">
    <h4>errors</h4>
    <ol>
    </ol>
</div>

现在验证有两个问题。如果所有字段都留空,当我只需要一个时,我会收到 3 条错误消息!

另外,如果我在其中一个输入中输入一个字母,我会得到一秒钟的“仅限数字”错误消息,但无论如何表单仍然提交,因为至少有 1 个字段被填写的第二次测试弥补了没有位数。

我这样做是完全错误的吗?我在这里或 jquery 论坛上找不到的示例似乎都不完全适合。我应该去什么方向来解决这个问题?

4

2 回答 2

4

看来我找到了解决方案。请参阅代码中的注释。现场演示

jQuery.validator.addMethod(
    "require_from_group", function(value, element, options) {
  var numberRequired = options[0];
  var selector = options[1];
  var fields = $(selector, element.form);
  var filled_fields = fields.filter(function() {
    // it's more clear to compare with empty string
    return $(this).val() != ""; 
  });
  var empty_fields = fields.not(filled_fields);
  // we will mark only first empty field as invalid
  if (filled_fields.length < numberRequired && empty_fields[0] == element) {
    return false;
  }
  return true;
// {0} below is the 0th item in the options field
}, jQuery.format("Please fill out at least {0} of these fields."));

$(document).ready(function(){
  var container = $('#errorContainer');
  $("#FORMMM").validate(  {

    // We must to force validation of entire form because
    // when we remove value from 2-nd field 
    // the 1-st field becomes invalid.
    onfocusout: function() { $("#FORMMM").valid() },
    onkeyup: function() { $("#FORMMM").valid() },

    rules: {
      // note: you can use variable to avoid repeating 
      // of the same code
      groceries: { 
        number: true,
        require_from_group: [1, ".at_least_one"]
      },
      gas: {
        number: true,
        require_from_group: [1,".at_least_one"]
      },
      hotels: {
        number: true,
        require_from_group: [1,".at_least_one"]
      }
    },
    success: function(label) {  
      label.html(" ").addClass("checked"); 
    },
    errorContainer: container,
    errorLabelContainer: $("ol", container),
    wrapper: 'li',
    meta: "validate"
  });
});
于 2012-05-04T18:38:38.767 回答
1

你有两个问题:

  1. 未通过数字检查不会阻止表单提交 - 您会看到消息,但随后会提交。
  2. 如果三个字段都不存在,您将收到三次错误消息。

你可以在这里看到开始状态:http: //jsfiddle.net/jclark/NR29t/1/;我唯一改变的是表单现在在提交而不是提交表单时会触发警报。

一次拿这些,我将从#1开始。我注意到如果非数字条目在表单的最后一个字段上,数字检查阻止表单提交。否则,它将继续。原来问题出在你的require_from_group方法上。正如它所写,重新验证整个表单:

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

阅读您链接的帖子以及那里链接的帖子,这似乎会导致错误消息在第一个必需的输入失去焦点时立即出现,而不是仅在提交时出现。对您的使用有要求吗?因为这似乎是第一个问题的原因。“being_validated”逻辑阻止了无限链(其中元素一重新验证元素二,它重新验证元素一,无限期),但是,这仍然意味着当每个字段被检查时,它将重新验证组表单中的所有字段。看起来这种重新验证导致了问题。我认为正在发生的事情是,如果第一个字段不是数字,则会记录该错误,但是当验证最后一个字段时,它会重新验证整个表单,但是 skip-inifite-loop 检查会导致其他字段被跳过;

我有 98% 的把握我做对了。但是,我确实知道删除该块可以解决问题。看到这个版本:

http://jsfiddle.net/jclark/NR29t/2/

现在来说第二个问题。在字段上显示所有错误的行为是设计使然,并且通常是有意义的——只是不是一组字段像这样相互关联。幸运的是,Validator 提供了一个groups选项,表示一组应该只报告发现的第一个错误的字段。看到这个版本:

http://jsfiddle.net/jclark/NR29t/3/

提交时未填写任何字段,您只会看到一条消息。但是,有一个新问题:“请仅输入数字”消息仅在您留下无效输入或该字段获得焦点后立即显示。我认为这是一个验证器错误;看到这个堆栈溢出问题: jquery validate-groups and their labels。具体来说,如果输入 3 被填充但不是数字,那么输入 1 和 2 是有效的(不包含非数字,并且填充了其他一些字段),所以我认为这是清除组的错误。

不幸的是,我目前不解决这个问题。上面链接的 SO 问题提出了一个有点脆弱的解决方法,即编写一个专门用于一次检查所有字段的验证方法,因此它们都失败了并且消息仍然存在。这是一个演示:

http://jsfiddle.net/jclark/NR29t/4/

这是自定义验证器:

jQuery.validator.addMethod("digits_for_group", function(value, element, selector) {
    var validOrNot = $(selector, element.form).filter(function() {
         // Each field is kept if it has a value
         return $(this).val().search(/[^0-9]/) != -1;
         // Set to true if there are enough, else to false
      }).length == $(selector, element.form).length;
    return validOrNot;

}, jQuery.format("Please enter only digits"));

它有效,但我不喜欢它;它需要重新实现数字检查;如果你有其他验证检查,你需要做同样的事情。

希望这可以帮助。

于 2012-05-04T19:00:39.117 回答