Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an "at least one of many required" functionnality to the form validation #868

Closed
agagnon opened this issue Dec 14, 2012 · 30 comments
Closed

Comments

@agagnon
Copy link

agagnon commented Dec 14, 2012

Would it be possible to have a "one of the above" required field feature. My example is a feedback form in which I have 3 text fields that the visitor can fill. I need to have at least one field with an answer but it can be any of them. So if the 3 fields are empty, it would throw an error.

@LaurentGoderre
Copy link
Member

Since this feature leverages jquery validation we could propose this addition to them and even send them a pull request with this, assuming it doesn't already exist (I don't remember seeing it though)

@patheard
Copy link
Member

You can do the above with a dependency callback. Conditional validation for 2 fields is supported with the WET plugin using dependency expressions:

<input id="phone" name="phone" type="tel" class="{validate:{required:'#email:blank'}}" />
<input id="email" name="email" type="email" class="{validate:{required:'#phone:blank'}}" />

The above makes each field required based on the result of the required selector:

var phoneRequired =  $('#email:blank').length > 0;
var emailRequired =  $('#phone:blank').length > 0;

If anyone can think of a selector that only returns a result if 2 or more fields are empty, dependency expressions will do the trick.

<!-- '&&' doesnt' work, but this idea -->
<input id="phone" name="phone" type="tel" class="{validate:{required:'#email:blank && #phone:blank'}}" />

@patheard
Copy link
Member

Figured it out while walking the dog. You can use the adjacent sibling selector to create an "at least one of many" required condition. For the following HTML, this selector will only return a result if all 3 fields are blank:

#field1:blank + label + #field2:blank + label + #field3:blank
<label for="field1"><span class="field-name">Field 1</span></label>
<input id="field1" name="field1" type="text" class="{validate:{required:'#field1:blank + label + #field2:blank + label + #field3:blank'}}" />

<label for="field2"><span class="field-name">Field 2</span></label>
<input id="field2" name="field2" type="text" class="{validate:{required:'#field1:blank + label + #field2:blank + label + #field3:blank'}}" />

<label for="field3"><span class="field-name">Field 3</span></label>
<input id="field3" name="field3" type="text" class="{validate:{required:'#field1:blank + label + #field2:blank + label + #field3:blank'}}" />

@LaurentGoderre
Copy link
Member

@patheard very cool! @agagnon does this meet your requirement?

@agagnon
Copy link
Author

agagnon commented Dec 17, 2012

Hard to tell if it actually works. By that, I mean that the only way I will get a validation error is when all fields are empty. In parheard example, I do get an error message, but it only says that the first field is required, which is the same result as if the first field is required and not the others.

So, the validation itself seems to be working fine, but the message never specifies that "one of the fields" must be filled, it just says that the first field is required.

@LaurentGoderre
Copy link
Member

Then perhaps this needs to be fleshed out a bit more.

@patheard
Copy link
Member

jQuery validation just gave me a better way of doing this using the require_from_group method:

<label for="field1"><span class="field-name">Field 1</span></label>
<input id="field1" name="field1" type="text" class="conditional {validate:{require_from_group: [1,'.conditional']}}" />

<label for="field2"><span class="field-name">Field 2</span></label>
<input id="field2" name="field2" type="text" class="conditional {validate:{require_from_group: [1,'.conditional']}}" />

<label for="field3"><span class="field-name">Field 3</span></label>
<input id="field3" name="field3" type="text" class="conditional {validate:{require_from_group: [1,'.conditional']}}" />

All that would be needed on our end is a translated version of the error message:

Please fill at least {0} of these fields.

Does this work for you @agagnon? In my testing it displayed an appropriate error message on all three fields and cleared the message once at least one of the fields had a value.

@agagnon
Copy link
Author

agagnon commented Dec 17, 2012

@patheard Much better. Unless it changed in the last few weeks, since this validation is "validateAdditional-min.js", the error message is only in English, there are no French version.

@patheard
Copy link
Member

@agagnon Glad to hear and yeah, we'd need to add the French version of the error to messages_fr.js.

@agagnon
Copy link
Author

agagnon commented Dec 18, 2012

When a field is required in a form, we have to tell the user that it is required.
Example: First Name (required)

What would we tell the user in this case?

@pjackson28
Copy link
Member

Have a fieldset + legend that says one of the contained fields must be filled in.

@ghost ghost assigned nschonni Feb 8, 2013
@pjackson28
Copy link
Member

Could someone please add this to the form validation working examples and documentation so this issue can be closed?

@patheard
Copy link
Member

patheard commented Mar 6, 2013

In adding the demo, I've run into jquery-validation/jquery-validation#412 (disables validation for any rules defined before require_from_group rule).

I tested the patched require_from_group method from SO and it the problem goes away.

@pjackson28
Copy link
Member

Does the problem go away in jQuery Validation 1.11.0 as well?

@patheard
Copy link
Member

patheard commented Mar 6, 2013

I haven't tested with 1.11.0, but the call to valid() that triggers the bug still exists in 1.11.0 and jquery-validation's master additional-methods.js.

@RitchieD
Copy link

I would also benefit from this. (Love those dog walking solutions!)
Would someone please post a more detailed demo?
I can't figure out how to implement from reading this issue.

@patheard
Copy link
Member

@RitchieD Here's a walkthrough of the above example. I've re-pasted it below so you don't have to scroll back and forth.

  1. Fields 1, 2 and 3 are conditionally required (at least one must be specified).
  2. To create this conditional relationship, the CSS class conditional is added to each <input>. The name of the CSS class isn't important - it's just a way of linking the three fields together for the validation rule.
  3. Finally, the conditional validation rule, require_from_group, is added to the three input fields using CSS class metadata: {validate:{require_from_group: [1,'.conditional']}}. This bit of code states the following:
    • Add the require_from_group validation rule to this field.
    • To be valid, this instance of the rule must find at least 1 populated input field with the CSS class conditional. If you wanted to make 2 fields conditionally required, you would add the rule like so: {validate:{require_from_group: [2,'.conditional']}}
<label for="field1"><span class="field-name">Field 1</span></label>
<input id="field1" name="field1" type="text" class="conditional {validate:{require_from_group: [1,'.conditional']}}" />

<label for="field2"><span class="field-name">Field 2</span></label>
<input id="field2" name="field2" type="text" class="conditional {validate:{require_from_group: [1,'.conditional']}}" />

<label for="field3"><span class="field-name">Field 3</span></label>
<input id="field3" name="field3" type="text" class="conditional {validate:{require_from_group: [1,'.conditional']}}" />

So, the cole's notes version is:

  1. Add a unique CSS class to the fields that are part of the conditionally required group.
  2. Add the CSS metadata {validate:{required_from_group...}} that sets how many fields are required and the CSS class ot look for.

Does this help clear things up?

@RitchieD
Copy link

@patheard Execellant! Thanks.

@pjackson28
Copy link
Member

@patheard Could you please update the working examples with this so people can find a live example of how to do this?

@patheard
Copy link
Member

@pjackson28 Sure, but because of the bug in the require_from_group rule we need to do one of the following:

  1. Create new demo page with only require_from_group example (hide bug).
  2. Move the require_from_group example to the top of the demo page (also hiding the bug).
  3. Fix the bug. I've found another fix referenced in require_from_group bug jquery-validation/jquery-validation#551 that works nicely.

Option 3 is the way to go, but I need to dig into it and figure out why a fix hasn't been submitted against jquery-validation yet (the above issue has been closed).

@pjackson28
Copy link
Member

What is the status on this issue? Has option 3 happened yet?

@patheard
Copy link
Member

No - the problem with the fix I found is that it breaks if there is more than one require_from_group rule used on a page. An alternate fix in jquery-validation/jquery-validation#814 isn't moving either.

@pjackson28
Copy link
Member

What should be done about this then? Any suggestions?

@patheard
Copy link
Member

I've been playing with it this afternoon and so far still no solid fix. The best I've come up with is similar to the above fix where it works as long as there's only one require_from_group rule in the form:

jQuery.validator.addMethod("require_from_group", function(value, element, options) {
    var validator = $.extend({}, this),  // clone form validator to prevent overwrite of rules
        fields = $(options[1], element.form),
        isValid = fields.filter(function() {
            return validator.elementValue(this);
        }).length >= options[0];

    if (!$(element).data('being_validated')) {
        fields.data('being_validated', true);
        fields.each(function() {
            validator.element(this);
        });
        fields.data('being_validated', false);
    }
    return isValid;

}, jQuery.format("Please fill at least {0} of these fields."));

Since upstream looks like they'll only merge a true fix (which makes sense), a possible solution for us would be to override the validateAdditional require_from_group method with a less broken version in our plugin.

Downside being that if it's ever fixed upstream, we'd need to remember to delete our monkey patch.

@nschonni
Copy link
Member

@patheard let me know if you find something solid, as I do have the commit bit for jquery validation

@patheard
Copy link
Member

Aw yeah - just figured out that my fix is good (when I was testing last night I had duplicated field names). I've submitted jquery-validation/jquery-validation#873 upstream.

@pjackson28 As a temp fix, do you want me to patch WET's copy of validateAdditional.js when/if my PR is merged?

@pjackson28
Copy link
Member

@patheard I think it is better to just wait on jQuery validation for this one (especially considering the involvement of @nschonni). At the very worst it can be introduced in v4.0.

@LaurentGoderre
Copy link
Member

@nschonni, has this been integrated into jQuery validation?

@nschonni
Copy link
Member

Yes, this is part of 1.12.0, but we haven't updated yet as there are more a11y fixes comming

@LaurentGoderre
Copy link
Member

Closing since v4.0 uses jQuery Validation 1.13.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants