最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - jquery form validation require one of a group of inputs AND require that input is an integer - Stack Overflow

programmeradmin0浏览0评论

I'm making a form that requires at least one field to be filled AND all inputs have to be either integers or decimals. I'm using jquery's validation plugin to validate. I've reworked something I found here that seems to partially do the trick. right now I have:

<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>

the HTML is below, in my actual form there are 15 input fields, I'm just condensing it for here:

<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>

Right now there are two problems with the validation. If all fields are left blank, I get 3 error messages when I only need one!

Also, if I enter a letter into one of the inputs, I get the "digits only" error message for a second, but the form still submits anyways, since the 2nd test of having at least 1 field be filled makes up for not having digits.

Am I doing this in a totally wrong way? None of the examples I can find here or on the jquery forums seem to fit exactly. What direction should I go to solve this?

I'm making a form that requires at least one field to be filled AND all inputs have to be either integers or decimals. I'm using jquery's validation plugin to validate. I've reworked something I found here that seems to partially do the trick. right now I have:

<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>

the HTML is below, in my actual form there are 15 input fields, I'm just condensing it for here:

<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>

Right now there are two problems with the validation. If all fields are left blank, I get 3 error messages when I only need one!

Also, if I enter a letter into one of the inputs, I get the "digits only" error message for a second, but the form still submits anyways, since the 2nd test of having at least 1 field be filled makes up for not having digits.

Am I doing this in a totally wrong way? None of the examples I can find here or on the jquery forums seem to fit exactly. What direction should I go to solve this?

Share Improve this question edited May 23, 2017 at 12:11 CommunityBot 11 silver badge asked May 1, 2012 at 21:16 pg.pg. 2,5316 gold badges44 silver badges69 bronze badges 4
  • For the sake of all that is holy in web development, please use <label for="input-id-name"> in your form; it makes forms much more accessible and user-friendly. – Moses Commented May 3, 2012 at 21:46
  • Oh I will do that, it's a good point I was just trying to get the js to work first and then I figured I would set the labels, placeholders etc. – pg. Commented May 3, 2012 at 23:04
  • And don't worry I'm not using these ugly tables either, I just wrote it that way for now and am planning to fix once I can figure out how to make errors display. – pg. Commented May 3, 2012 at 23:30
  • You should probably award one of answers. – Pavel Strakhov Commented May 9, 2012 at 16:23
Add a ment  | 

2 Answers 2

Reset to default 4 +50

It seems I found a solution. See ments in code. Live demo.

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 pare 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 bees 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"
  });
});

You have two problems:

  1. Failing the digits check doesn't prevent the form from submitting - you see the message, but then it submits.
  2. If none of the three fields are present, you get the error message three times.

You can see the starting state here: http://jsfiddle/jclark/NR29t/1/; the only thing I changed is that the form now fires an alert when submitted instead of submitting the form.

Taking these one at a time, I'll start with #1. I noticed that the digit check will stop the form from submitting, if the non-digit entry is on the last field of the form. Otherwise, it will continue. It turns out the problem is in your require_from_group method. As it written, re-validates the whole form:

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

Reading through the post you linked, and the posts linked there, this appears to be present to cause the error message to appear as soon as the first required input loses focus, instead of only on submit. Is the a requirement for your use? Because this seems to be the cause of the first issue. The "being_validated" logic prevents a infinite chain (where element one revalidates element two, which revalidates element one, ad infinitum), but, this still means that as each field is checked, it will revalidate the all fields in the group form. It looks like this revalidation is causing the problem. I think what is happening is if the first field is non-digit, that error is noted, but when the last field is validated, it revalidates the whole form, but the skip-inifite-loop check causes the other fields to be skipped; since the last field is valid, the whole form submits.

I'm about 98% sure I've got that right. I do know, however, that removing that block eliminates the problem. See this version:

http://jsfiddle/jclark/NR29t/2/

Now for the second issue. The behavior of showing all errors on the field is by design, and usually makes sense - just not a group of fields are inter-related like this. Fortunately, Validator provides the groups option, to denote a group of fields that should only report the first error found. See this version:

http://jsfiddle/jclark/NR29t/3/

Submit with no fields filled in, and you only see one message. However, there's a new problem: the "Please enter only digits" message only shows immediately after you leave an invalid input, or when the field is focused. I think this is a Validator bug; see this Stack Overflow question: jquery validate - groups and their labels. Specifically, if input 3 is populated but not a digit, then input 1 and two are valid (the don't contain non-digits, and some other field is populated), so I think that is clearing out the error for the group.

Unfortunately, I don't fix for that issue at this time. The linked SO question above suggests a somewhat fragile workaround of writing a validation method specifically to check all fields at once, so they all fail together and the message stays. Here's a demo of that:

http://jsfiddle/jclark/NR29t/4/

Here's the custom validator:

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

It works, but I don't love it; it requires re-implementing the digits check; it you have other validation checks you'd need to do the same.

Hope this helps.

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论