4

I'm using jQuery Validate and would like to re-validate a group of fields whenever one of them is changed (or possibly, whenever one of them validates successfully). My attempts so far just create infinite loops.

Is this possible, or does the plugin design preclude it?

(Specifically, I've got a method that requires at least X of group Y to be filled out, and as soon as that's true, I'd like all those fields to re-validate. Currently I'm clearing out their error messages with my own code, but that's a hack - it also hides unrelated validation problems until the form is re-submitted.)

Community
  • 1
  • 1
Nathan Long
  • 122,748
  • 97
  • 336
  • 451

2 Answers2

11

The validate method has a few options to support re-validating on change, namely these:

$(".selector").validate({
  onfocusout: true,
  onkeyup: true,
  onclick: true,
  //The rest of your options
});

These all default to false, but should offer the functionality you mention in the question.

Update based on comments: Given a simple test form like this:

<form action="get">
    <div><input type="text" name="part1" class="part"></div>
    <div><input type="text" name="part2" class="part"></div>
    <div><input type="text" name="part3" class="part"></div>
    <div><input type="text" name="part4" class="part"></div>
    <input type="submit" value="Submit" />
</form>

The jQuery would be the following:

jQuery.validator.addMethod("require_from_group", function(value, element, options) {
    var valid = $(options[1], element.form).filter(function() {
        return $(this).val();
    }).length >= options[0];

    if(!$(element).data('reval')) {
        var fields = $(options[1], element.form);
        fields.data('reval', true).valid();
        fields.data('reval', false);
    }
    return valid;
}, jQuery.format("Please fill out at least {0} of these fields."));

$("form").validate({
    rules: {
        part1: { require_from_group: [2,".part"] },
        part2: { require_from_group: [2,".part"] },
        part3: { require_from_group: [2,".part"] },
        part4: { require_from_group: [2,".part"] }
    }
});​

You can play with a demo here, see if this is what you're after: http://jsfiddle.net/mhmBs/

The method here uses .data() to let an element know not to cause an infinite loop. The actual element that is being edited, on blur (normal cause for validation triggers) re-validates only the other elements in the selector you specified in the group, so not the whole form like my comment...it's only triggering it on the minimum number of elements. ​

Austyn Mahoney
  • 11,398
  • 8
  • 64
  • 85
Nick Craver
  • 623,446
  • 136
  • 1,297
  • 1,155
  • Each of these options has to do with re-validating the current field. I'm trying to re-validate fields related to the current one. In other words, to say 'if this field passes validation, validate the two other fields of the same class' or something similar. – Nathan Long Apr 07 '10 at 12:42
  • 1
    @Nathan - Is triggering the full form to re-validate an option, upon change of these fields? – Nick Craver Apr 07 '10 at 12:44
  • @Nathan - Updated with what I *think* is what you're after, let me know if not. – Nick Craver Apr 08 '10 at 19:56
  • @Nick - this is great! I added to your demo to verify that when this test passes, it doesn't clear any other errors, such as 'this must be a number.' – Nathan Long Apr 09 '10 at 16:03
  • @Nick - I wasn't familiar with `.data()` - very interesting. Thanks for the lesson and for the demo of your solution. You have thoroughly earned the rep for this one. – Nathan Long Apr 09 '10 at 16:08
  • @Nick - P.S. - why did you select both the selector that was passed in AND element.form? – Nathan Long Apr 09 '10 at 16:23
  • @Nathan - It's not selecting both, but rather that selector only inside the current form, it's the `$(selector, context)` style, by default if you don't pass one, it's `document`, so this: `$(selector)` is *really*: `$(selector, document)`, which internally calls: `$(document).find(selector)`. In this case we're telling to to search for the selector, but **only** inside the current form, which with the validation plugin (being per-form) is the only elements the rule applies to. If you look inside the validation plugin, you'll see lots of `selector, element.form)` as well, same reason. – Nick Craver Apr 09 '10 at 16:27
  • @Nick - gotcha. I thought you were doing this: http://api.jquery.com/multiple-selector/. I haven't seen that way of giving context and don't see it at api.jquery.com - the only way I knew was like `$('form#foo input')`. Do you have to pass in two jQuery objects for this context limiter? Also, what's up with `element.form`? Is that a generalizable thing? I originally did `$(element).parents('form')` and don't quite get your way yet. – Nathan Long Apr 09 '10 at 16:48
  • @Nathan - You can read about the `$()` [overloads here](http://api.jquery.com/jQuery/). It can take a number of things, a DOM element (like this case), a document, or a jquery object. `element.form` [is a DOM element property](http://msdn.microsoft.com/en-us/library/ms533768.aspx), just base javascript. The closest thing in jQuery would be: `$(element).closest('form').get(0)` – Nick Craver Apr 09 '10 at 16:52
  • @Nick - so great. Thanks again for all the help; this has been very educational. – Nathan Long Apr 09 '10 at 17:48
  • @Nathan - Welcome :) I might end up using this same approach somewhere, thanks for sharing it in the original question...I'd update that with your final result, it is a *very* common situation. – Nick Craver Apr 09 '10 at 18:03
  • @Nick - done. I sacrificed the conciseness of your code for a more explanatory approach, once I figured out how that 'reval' part worked. :) FYI - I have a related 'fill X of these or just skip them all' rule that I will also update with your approach. Maybe it will be useful for you, too. It's here: http://stackoverflow.com/questions/1888976/jquery-validate-either-skip-these-fields-or-fill-at-least-x-of-them – Nathan Long Apr 09 '10 at 18:36
  • Why the validator overrides the first items to validate, group is into last part. – text May 20 '10 at 12:46
  • I changed your solution by adding a new required field - this field isn't validated by pressing the submit button. How could this be? http://jsfiddle.net/xsQtJ/ – Martijn B Dec 08 '10 at 13:46
  • In response to Nick Craver's solution: Any required inputs that appear before the group will not be checked for validation unless focus is placed on the specific field after validation check. Inputs that appear after the group work fine. example: http://jsfiddle.net/mhmBs/132/ (try submitting with nothing in the fields) –  Dec 21 '10 at 21:19
1

Dont know how this worked but, just found that removing the below part:

if(!$(element).data('reval')) {
        var fields = $(options[1], element.form);
        fields.data('reval', true).valid();
        fields.data('reval', false);
}

of code from the main code make all the validations to work as normal and expected. :)