51
votes

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?

11
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
This is a single form where the visibility of the Login/Signup fields are toggled by the radio button.Bullines
the validate method can only be called once per form. Think of it as an initialization. Take a look at this post for details.lboullo0

11 Answers

60
votes

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.

40
votes

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")
        }
      }
    }
  }
});
11
votes

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

9
votes

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

4
votes

try this..

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

credit from here.

3
votes

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",
  ...
1
votes

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;
}
0
votes

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

});
0
votes

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

});
0
votes

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};
-3
votes

the below code is working superb...

.validate({
  ignore: ":not(:visible),:disabled",
  ...