Note that there are some explanatory texts on larger screens.

plurals
  1. POjQuery Validate - require at least one field in a group to be filled
    text
    copied!<p>I'm using the excellent jQuery <a href="http://docs.jquery.com/Plugins/Validation" rel="nofollow noreferrer">Validate Plugin</a> to validate some forms. 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. <strong>Please suggest any improvements you can think of.</strong></p> <p>Finding no built-in way to do this, I searched and found <a href="http://rmurphey.com/blog/2009/04/15/jquery-validation-indicate-that-at-least-one-element-in-a-group-is-required/" rel="nofollow noreferrer">Rebecca Murphey's custom validation method</a>, which was very helpful. </p> <p>I improved this in three ways:</p> <ol> <li>To let you pass in a selector for the group of fields</li> <li>To let you specify how many of that group must be filled for validation to pass</li> <li>To show all inputs in the group as passing validation as soon as one of them passes validation. (See shout-out to <a href="https://stackoverflow.com/users/13249/nick-craver">Nick Craver</a> at end.)</li> </ol> <p>So you can say <strong>"at least X inputs that match selector Y must be filled."</strong></p> <p>The end result, with markup like this:</p> <pre><code>&lt;input class="productinfo" name="partnumber"&gt; &lt;input class="productinfo" name="description"&gt; </code></pre> <p>...is a group of rules like this:</p> <pre><code>// 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"] } </code></pre> <p>Item #3 assumes that you're adding a class of <code>.checked</code> to your error messages upon successful validation. You can do this as follows, <a href="http://jquery.bassistance.de/validate/demo/milk/" rel="nofollow noreferrer">as demonstrated here</a>.</p> <pre><code>success: function(label) { label.html(" ").addClass("checked"); } </code></pre> <p>As in the demo linked above, I use CSS to give each <code>span.error</code> an X image as its background, unless it has the class <code>.checked</code>, in which case it gets a check mark image.</p> <p>Here's my code so far: </p> <pre><code>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 &gt;= 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.")); </code></pre> <p>Hooray!</p> <h2>Shout out</h2> <p>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 <a href="https://stackoverflow.com/questions/1378472/jquery-validate-can-i-re-validate-a-group-of-fields-after-changing-one">I asked a question</a>, and <a href="https://stackoverflow.com/users/13249/nick-craver">Nick Craver</a> enlightened me. Thanks, Nick!</p> <h2>Question Solved</h2> <p>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!</p> <h1>Update - now part of jQuery Validation</h1> <p>This was <a href="https://github.com/jzaefferer/jquery-validation/commit/78a739f7c574c80547dfecd70b46a362efc8e8a7" rel="nofollow noreferrer">officially added to jQuery Validation</a> on 4/3/2012.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload