55

I have a single form that, depending on which radio button is clicked (Login or Signup), displays either:

  • email address
  • password

or:

  • name
  • age
  • email address
  • password

Clicking on the radio button toggles the visibility of the Login/Signup fields:

<form id="myForm">
    <input name="userAction" type="radio" value="login" checked="checked">Login</input>
    <br />
    <input name="userAction" type="radio" value="signup">Sign Up</input>

    <div id="loginFields" style="display:none">
        <!-- Login fields (email address and password) -->
    </div>

    <div id="signupFields" style="display:none">
        <!-- Signup fields (name, age, email address, password) -->
    </div>
</form>

I'm using the jQuery Validation plug-in, and I'd like to use the following rules:

var signupRules = {
    emailAddressTextBox:
    {
        required: true,
        email: true 
    },
    passwordTextBox:
    {
        required: true,
        minlength: 6,
        maxlength: 24,
        passwordValidationRule: true // custom regex added with $.validator.addMethod()
    }
};

var loginRules = {
    nameTextBox:
    {
        required: true,
        maxlength: 50
    },
    loginEmailAddressTextBox:
    {
        required: true,
        email: true 
    },
    loginPasswordTextBox:
    {
        required: true,
        minlength: 6,
        maxlength: 24,
        passwordValidationRule: true // custom regex added with $.validator.addMethod()
    },
    loginPasswordAgainTextBox:
    {
        required: true,
        minlength: 6,
        maxlength: 24,
        equalTo: "#loginPasswordTextBox"
        passwordValidationRule: true // custom regex added with $.validator.addMethod()        
    }
};

How can I add the correct validation rule dynamically based on:

   $("input[name='userAction']").change(function() {
        if ($("input[name='userAction']:checked" ).val() === "login") {
            // use loginRules
        } else {
            // use signupRules
        }
    });

I've tried the following:

$("#myForm").validate({
    rules: ($("input[name='userAction']:checked" ).val() === "login") ? loginRules : signupRules;
});

But since my Login fields are the default displayed, its validations work, but the Signup scenario doesn't; it wants to validate Login fields for some reason. Am I missing something?

Bullines
  • 5,626
  • 6
  • 53
  • 93
  • are you replacing the elements within a form, or are you showing hidden elements within a form? I would set up the validation for two separate forms and then toggle the visibility of the two forms depending on which option is selected. – zzzzBov Nov 08 '10 at 22:23
  • This is a single form where the visibility of the Login/Signup fields are toggled by the radio button. – Bullines Nov 08 '10 at 22:25
  • the validate method can only be called once per form. Think of it as an initialization. Take a look at [this post](http://suntouchersoftware.com/2013/07/05/tips-for-using-the-jquery-validation-plugin/) for details. – lboullo0 Dec 12 '13 at 16:08

11 Answers11

61

Ahh validation plugin, always so tricky :(

First, I added id attributes to all the input boxes. Then, I made a change function for you:

$("input[name='userAction']").change(function() {
    $('#signupFields').toggle();
    $('#loginFields').toggle();    
    if ($("input[name='userAction']:checked").val() === "login") {
        removeRules(signupRules);
        addRules(loginRules);
    } else {        
        removeRules(loginRules);
        addRules(signupRules);

    }
});

The add and remove functions look like this:

function addRules(rulesObj){
    for (var item in rulesObj){
       $('#'+item).rules('add',rulesObj[item]);  
    } 
}

function removeRules(rulesObj){
    for (var item in rulesObj){
       $('#'+item).rules('remove');  
    } 
}

That's pretty much it. See here for a working example: http://jsfiddle.net/ryleyb/wHpus/66/

EDIT: To me, the non-intuitive part is that I don't see an easy way to add/remove rules to the whole form after you call validate, instead you have to manipulate the individual form elements.

Ryley
  • 21,046
  • 2
  • 67
  • 81
  • I'm seeing a "$.data(element.form, 'validator') is undefined" error. – Bullines Nov 09 '10 at 01:11
  • on my jsfiddle, or when you use it in your code? If its yours, did you add id tags to all your form elements? – Ryley Nov 09 '10 at 01:32
  • 2
    I see the error in my code. It turns out that I wasn't adding the validate() before applying the rules. That makes all the difference :) Thanks. – Bullines Nov 09 '10 at 01:50
  • 1
    With version 1.13.0 I found I can remove the whole rule set by overwriting it. See: http://stackoverflow.com/a/24829279/866236 – Dan Jul 18 '14 at 16:11
  • Use the depends callback. – robert May 07 '15 at 15:05
  • @robert - That would work well for some rules, but given the volume of rules given here, I think it would be inappropriate - you'd have ~20 different depends functions. Surely this method is easier to understand? – Ryley May 07 '15 at 15:55
  • The problem with using add/remove of the rules is that it does not change the text currently displayed. So the user still sees an out-of-date validation error. – user959690 Dec 03 '15 at 18:37
  • @Ryley, is there a way to trigger validation when a rule's parameter changes? I'd be grateful if you could take a look at my question [here](https://stackoverflow.com/q/62967270/10841085). I haven't been able to find anything in the docs that would facilitate this besides `.valid()`, but as I am new to the plugin and web development in general, I thought I'd ask the community just to be sure. – user51462 Jul 19 '20 at 00:36
41

Or you can use the depends property.

http://jqueryvalidation.org/category/plugin/ search for depends

Example: Specifies a contact element as required and as email address, the latter depending on a checkbox being checked for contact via email.

$(".selector").validate({
  rules: {
    contact: {
      required: true,
      email: {
        depends: function(element) {
          return $("#contactform_email:checked")
        }
      }
    }
  }
});
robert
  • 871
  • 8
  • 15
  • It is an example of how he can use it. Instead of adding/removing rules it is better to make them conditional. – robert Jan 30 '13 at 21:56
  • You are correct. However, it's an example without explanation, and not even a complete working solution. `depends` will only work on `rules` that can be declared with a `true` or `false`... not any of the others. It would be better in the OP's more complex case to swap out entire sets of rules as fully demonstrated in the accepted answer. – Sparky Jan 30 '13 at 22:04
  • @Sparky i don't agree with the accepted answer, my proposition is shorter and less complicated and you could extract the depends function as a callback method to reuse it for other fields. But hey not everybody likes clean code or don't even know how to code. – robert May 07 '15 at 15:13
  • 1
    Firstly, the OP's exact situation is more complex than can be accomplished with a single `depends`. Secondly, you're responding to a comment made almost two years ago. – Sparky May 07 '15 at 15:27
  • I agree with Sparky - expand that to include all 19 rules that OP gave, and then let us judge your answer on that. – Ryley May 07 '15 at 15:56
13

This post is from years ago, but since it has been viewed a lot of times, I think it would be useful to say that the jQuery Validation plugin now allows us to read, add and remove rules.

Some examples:

  1. Print all rules attached to #myField: console.log($('#myField').rules());

  2. Remove an unwanted rule: $('#myField').rules('remove', 'min');

  3. Add a new rule: $('myField').rules('add', {min: 10});

So say if you want to dynamically update the minimum value required. You can call a remove and a add right after:

// Something happened. The minimum value should now be 100
$('#myField').rules('remove', 'min');
$('#myField').rules('add', {min: 100});

More information can be found here: https://jqueryvalidation.org/category/plugin/#-rules()

FlavioEscobar
  • 839
  • 1
  • 12
  • 19
10

If you want to call validate again with new settings (rules,messages ... etc.) call

$('#formid').removeData('validator')

This will remove validation for the form then initialize it again with the new settings

Boban Stojanovski
  • 892
  • 13
  • 26
  • There are built-in methods for changing rules dynamically. There is no need to wipe it out and re-initialize. – Sparky Jan 25 '13 at 22:00
  • could you tell us what methods exist for adding/removing rules dynamically? i could really use those , cause i am making spa apps and i have one validator object that i keep refreshing after page change. – Boban Stojanovski Jan 27 '13 at 01:11
  • It's [the `rules` method along with `add`](http://docs.jquery.com/Plugins/Validation/rules). See accepted answer above for how to use it. Also [browse my answers on this plugin for other ways](http://stackoverflow.com/search?q=user:594235%20%5Bjquery-validate%5D). – Sparky Jan 27 '13 at 01:19
  • Thats not what i am looking for , say i have page1 and validator object with rules for a form1 on that page , then i click a link to go to page2 and change the html of that form (no page refresh) how would i change the rules of the validator? are you saying i should use the for loop every time – Boban Stojanovski Jan 27 '13 at 12:05
  • If you have a question, post it as a question. Otherwise I've provided you with links to over a hundred other questions about this plugin that would lead you to a solution. – Sparky Jan 27 '13 at 15:29
  • 1
    finally your way is better, I use the same principe but whit two more lines $("form").data("unobtrusiveValidation", null); $("form").data("validator", null); $.validator.unobtrusive.parse($("form")); – chefjuanpi Dec 11 '14 at 04:50
  • @Sparky what's the problem with re-initialize? This way I dont need to control which rules I have to remove and add. Just simply re-initialize form-validation with the other rules. – m.rufca Aug 14 '15 at 12:56
4

try this..

rules: {
    address: {
       required: {
                   depends: function(element) {
                     if (....){
                       return true;}
                     else{
                       return false;}
                   }
                 }
             }
       }

credit from here.

wwanich
  • 61
  • 4
3

There is an option now to ignore fields bases on selector criteria, such as invisible or disabled, such that you wouldn't have to change your rule set:

.validate({
  ignore: ":not(:visible),:disabled",
  ...
jeeber
  • 59
  • 1
  • There's no practical way to apply your suggestion to the OP's scenario. (There are also built-in methods for changing rules.) – Sparky Jan 25 '13 at 22:01
  • This is a great suggestion if you are trying to dynamically toggle an element's validation on or off, but as stated above, doesn't apply to rules. – Ken Apr 10 '15 at 20:26
1

Take a look at my answer https://stackoverflow.com/a/20547836/1399001. It includes a working jsfiddle. In your example will be something like this:

$("input[name='userAction']").change(function() {

    var settings = $("#myForm").validate().settings;

      if ($("input[name='userAction']:checked" ).val() === "login") {
            $.extend(settings, {
              rules: loginRules
            });
    } else {
            $.extend(settings, {
              rules: signupRules
            });
    }


    $("#myForm").valid();

});
Community
  • 1
  • 1
lboullo0
  • 772
  • 7
  • 14
1

Keep track of the validation object and remove/replace rules directly. Works for me with v1.13.0

var validation = $('#form1').validate(); //Keep track of validation object

//Rule set 1
var validationRulesLogin = {
    headerEmail: {
        required: true,
        email: true
    },
    headerPassword: "required"
};
var validationMessagesLogin = {
    headerEmail: {
        required: "Please enter your email address.",
        email: "Not a valid email address."
    },
    headerPassword: "Please enter your password."
};

//Rule set 2
var validationRulesSignup = {
    signupEmail: {
        required: true,
        email: true
    },
    signupPassword: "required",
    signupPassword2: {
        equalTo: "#phBody_txtNewPassword"
    }
};
var validationMessagesSignup = {
    signupEmail: {
        required: "Please enter your email address.",
        email: "Not a valid email address."
    },
    signupPassword: "Please enter your password.",
    signupPassword2: "Passwords are not the same."
};

//Toggle rule sets
function validatingLoginForm(){
    validation.resetForm();
    validation.settings.rules = validationRulesLogin;
    validation.settings.messages = validationMessagesLogin;
}
function validationSignupForm(){
    validation.resetForm();
    validation.settings.rules = validationRulesSignup;
    validation.settings.messages = validationMessagesSignup;
}
Dan
  • 593
  • 8
  • 16
1

This can be easily done by updating the .validate().settings.rules

Example snippet below for password field which will be added with required rule.

$('#myForm').validate().settings.rules.password = {required: true};
0

I had a similar problem and solved it by adding a "requiredForLogin" class to all of the login textboxes, and "requiredForSignUp" class to all of the signup textboxes.

Then used jQuery's toggleClass, and jQuery.validate's addClassRules to turn on and off the rules depending on which button was pressed.

function EnableAllValidation() {
    // remove the jquery validate error class from anything currently in error
    //  feels hackish, might be a better way to do this
    $(".error").not("label").removeClass("error");

    // remove any the 'disabled' validation classes, 
    //  and turn on all required validation classes 
    //  (so we can subsequently remove the ones not needed)
    $(".requiredForLoginDisabled").toggleClass("requiredForLoginDisabled requiredForLogin");
    $(".requiredForSignUpDisabled").toggleClass("requiredForSignUpDisabled requiredForSignUp");
}
function EnableLoginValidation() {
    // reenable all validations
    //  then disable the signUp validations
    EnableAllValidation();
    $(".requiredForSignUp").toggleClass("requiredForSignUpDisabled requiredForSignUp");
}
function EnableSignUpValidation() {
    // reenable all validations
    //  then disable the login validations
    EnableAllValidation();
    $(".requiredForLogin").toggleClass("requiredForLoginDisabled requiredForLogin");
}
$(document).ready(function () {
    $("input[value='login']").click(function () {
        EnableLoginValidation();
    });
    $("input[value='signup']").click(function () {
        EnableSignUpValidation();
    });

    $("#myForm").validate();
    jQuery.validator.addClassRules({
        requiredForSignUp: {
            required: true
        },
        requiredForLogin: {
            required: true
        }
    });

});
-3

the below code is working superb...

.validate({
  ignore: ":not(:visible),:disabled",
  ...
ngrashia
  • 9,869
  • 5
  • 43
  • 58
  • 2
    This doesn't look like a good answer, so it should probably be downvoted, but I don't see grounds on which to delete it. Marking it as "Looks OK" in response to a flag someone else raised on it. – ArtOfWarfare Oct 20 '14 at 17:17