0
votes

I have an input form that I'm performing client-sided validation on with the jQuery validator plugin. Basic usage is working great, except for a specific scenario:

The form splits up address input fields, allowing separate fields for street number, name, city, state, and zip. The address itself is an optional input to the form (a user may opt to enter no address), but I want to ensure that if any one of these fields are used, the user is prompted to enter all the fields.

This works, except in the case when someone enters in an address and hits submit, and then decides to enter in no address. The ideal behavior in this case would be that, as soon as the text in the inputs they've entered is removed, for the address group to be unhighlighted.

Here is the current scenario:

  1. User enters information into only one input field, e.g., street name.
  2. The submit button is clicked.
  3. The validator plugin highlights the other address inputs with an error message prompting for the full address.
  4. User decides to enter no address, and removes the prior input, e.g. erases street name
  5. Ideally: All the other highlighted address inputs are unhighlighted and the error message is removed. Actually: The highlighted address inputs and message remain until form submission.

Here is the javascript that demonstrates the problem and the corresponding JSFiddle.

$("form").validate({
    errorClass: 'error',
    errorElement: 'label',
    submitHandler: function() {
        alert("Form submitted");
        return false;
    },
    groups: {
        address: "streetNumber streetName city state zipcode"
    },
    rules: {
        streetNumber: {
            required: {
                depends: function(){
                    return $("#streetName").val() != '' || $("#city").val() != '' || $("#state").val() != '' || $("#zipcode").val() != '';
                }
            }
        },
        streetName: {
            required: {
                depends: function(){
                    return $("#streetNumber").val() != '' || $("#city").val() != '' || $("#state").val() != '' || $("#zipcode").val() != '';
                }
            }
        },
        city: {
            required: {
                depends: function(){
                    return $("#streetNumber").val() != '' || $("#streetName").val() != '' || $("#state").val() != '' || $("#zipcode").val() != '';
                }
            }
        },
        state: {
            required: {
                depends: function(){
                    return $("#streetNumber").val() != '' || $("#streetName").val() != '' || $("#city").val() != '' || $("#zipcode").val() != '';
                }
            }
        },
        zipcode: {
            required: {
                depends: function(){
                    return $("#streetNumber").val() != '' || $("#streetName").val() != '' || $("#city").val() != '' || $("#state").val() != '';
                }
            }
        }
    },
    messages: {
        streetNumber: {required: "Must provide full address"},
        streetName: {required: "Must provide full address"},
        city: {required: "Must provide full address"},
        state: {required: "Must provide full address"},
        zipcode: {required: "Must provide full address"}
    },
    highlight: function(element, errorClass, validClass) {
        $(element).addClass(errorClass).removeClass(validClass);
    },
    unhighlight: function(element, errorClass, validClass) {
        $(element).removeClass(errorClass);
    },
    errorPlacement: function(error, element) {
        var n = element.attr("name");
        if (n == "streetNumber" || n == "streetName" || n == "city" || n == "state" || n == "zipCode")
                error.insertAfter("#zipcode");
    }
});

Besides trying to get the desired functionality of the highlight, I'm also wondering if there is a smarter way to accomplish the "all or nothing" input groups that doesn't involve the mess of conditional statements. Perhaps I can use a form input group?

3
When I put a console.log() in the highlight/unhighlight functions, I notice that when I clear the input they are never called, so that's probably part of the problem - Corey
You'll want your unhighlight callback function to do the opposite of your highlight callback function. More like this: $(element).removeClass(errorClass).addClass(validClass); - Sparky
BTW, highlight/unhighlight are only called when an error is triggered or cleared. In other words, the same time you see the error message appear and disappear. - Sparky

3 Answers

1
votes

You need to add a function on the focus event, then when the user leaves the field, the form fields will update.

It's difficult because you are using a plugin, so all the calls are happening inside that but I think something like this will work:

var inputs = $('form').find('input');
inputs.focus(function () {
    inputs.each(function () {
       $(this).removeClass('error');
    });
});

Just stick this in your code outside of the validate initialiser.

It would be even better if you defined your errorCode variable outside of the validator and then used that var in both functions, like this:

var errorClass = 'error';
$('form').validate({
    errorClass: errorClass,
...
...
});

var inputs = $('form').find('input');
inputs.focus(function () {
inputs.each(function () {
    $(this).removeClass(errorClass);
});
});
0
votes

you can try to add a method in the unhighlight: something like

$('.error').removeClass(errorClass);

or define related inputs and do

$('.relatedInputs').removeClass(errorClass);

you could also add an onChange function like

function(el){
   if(el.val() == ''){
    $('.relatedInputs').removeClass(errorClass);
   } 
}
0
votes

I was able to get desired functionality by using this:

onfocusout: function(element) {
    var inputs = $(element).closest('form').find('input, select');
    inputs.each(function() {
        if ($(this).valid())
            $(this).removeClass('error');
    });
}

Which was inspired from another post and DoubleA's answer. I haven't tested it thoroughly to see if it regresses anything, but so far it seems to work.