2
\$\begingroup\$

I've a jQuery validation script to check all form fields for a valid value and prevent form submission and display an error message if any fields fail. It was requested that the validation script not check fields one by one, but that it check and highlight ALL fields that failed validation. It works perfectly. But I am more a front-end person, than a real developer and even though it works I feel like it's twice as long as it needs to be.

I've tried to combine logic where I could but it still feels like I have a ton of if/else statements and it just doesn't seem very...well...elegant.

A little more background: The script is used by three different forms which each have a different number of fields (form 1 has only email, form 2 has email and country, form 3 has email, country, and gender). The script checks for a form ID before bothering to validate any fields that aren't there.

$("#footer_newsletter").submit(function(){
var hasValue = true;
var validEmail = true;
// validate email
if($.trim($("#newsletter_email").val()) == ""){
  $("#newsletter_email").addClass("error");
  hasValue = false;
}else{
  $("#newsletter_email").removeClass("error");
}if(!$("#newsletter_email").val().match(/^[A-Z0-9._%-]+@[A-Z0-9.-]+\.([A-Z]{2,4})$/i)){
  $("#newsletter_email").addClass("error");
  validEmail = false;
}else{
  $("#newsletter_email").removeClass("error");      
}
if(parseInt($("#newsletter_form_id").val()) > 0){ 
// validate country
  if($("#newsletter_country").prop("selectedIndex") == 0){
      $("#newsletter_country").addClass("error");
      hasValue = false;
  }else{
    $("#newsletter_country").removeClass("error");
  }
}
if(parseInt($("#newsletter_form_id").val()) > 1){
  // validate gender
  if($(".email_signup_form_wrapper :radio:checked").val() == undefined){
      $("#newsletter_gender").addClass("error");
      hasValue = false;
  }else{
    $("#newsletter_gender").removeClass("error");
  }
}
if(!validEmail && !hasValue){
  $("#error_required_field").show();
  return false;
}else if(!validEmail && hasValue){
  $("#error_valid_email").show();
  $("#error_required_field").hide();
  return false;      
}else if(validEmail && !hasValue){
  $("#error_required_field").show();
  $("#error_valid_email").hide();
  return false;      
}else if(validEmail && hasValue){
  $("#error_valid_email").hide();
  $("#error_required_field").hide();
  $("#newsletter_submit").hide();
  $("#newsletter_sending").show();
  $.ajax({ type: "get", url: $("#footer_newsletter").attr("action"), data: $("#footer_newsletter").serialize(), dataType: "script" });
  return false;
} 

My basic thinking behind the script is this:

  1. In all fields I have to check for a value, and in the email field I have to check for a VALID value so I create two variables at the top of the script to record whether a field has a value, and whether or not that value is valid if it's the email field.

  2. Look at each field and test it's value. If it fails add a class of "error", otherwise remove the class "error".

  3. Then, if any of the following are true: The form has empty fields and does not have a valid email address, or the form has all fields filled out but does not have a valid email address, or the form has a valid email address but not all fields are filled out then display the appropriate error message.

  4. Otherwise, everything looks good so submit the form.

Here is a fiddle where you can see it in action. For simplicity I've removed the submission bit and the command to show the loading graphic.

http://jsfiddle.net/judah/Ppewz/21/

\$\endgroup\$

3 Answers 3

1
\$\begingroup\$

I would recommend that you use the JQuery validation plugin (http://docs.jquery.com/Plugins/Validation) then your validation declaration would be as follows (fields which do not exist are ignored):

$("#footer_newsletter").validate(
    rules: {
            email: {
                    required: true,
                    email: true
                   },
            country: "required",
            gender: "required" 
    },
    messages: {
             email: {
                     required: "Please enter an email",
                     email: "Please enter a valid email address"
                    },
             country: "Please select a country",
             gender: "Please select your gender"
    }
);
\$\endgroup\$
2
  • \$\begingroup\$ Thanks ssmusoke, I did look into the the plugin but I was adapting a validation script that already existed in our app and I decided to take the opportunity to write my own. \$\endgroup\$
    – Judah
    Apr 6, 2012 at 16:33
  • 2
    \$\begingroup\$ You are welcome, I have always found that using pre-built and pre-tested plugins as they save a lot of time, since you do not re-invent the wheel \$\endgroup\$ Apr 6, 2012 at 17:49
0
\$\begingroup\$

split the individual validations and complete form validation. generalize the validations, something like here

$("#footer_newsletter").submit(function() {

    // send all fileds and their types to check form method   
    var invalidFields = checkForm({"type":"email","name":"some"},
                                     {"type":"field","name":"some2"});
    // it returns only those fields that have invalid data
    // invalidFields var has array of names of fields with invalid data

});

function checkEmail (email) {
    // validate single email field, return true if it is a valid email
}

function checkField (field) {
    // validate single field to check if it is empty, return true if it is not empty
}

function checkForm (jsonArray) {
    var invalidFieldsArray = new Array();

    // loop through every field details and send it to respective filed validator methods
    for(field in jsonArray) {

        if(field.type == 'email') {

            // returns true if it is valid email
            if(! checkEmail(field.name) {

                // if invalid save to array
               invalidFieldsArray.add(field.name);
            }
        } else if(field.type == 'field') {

            // returns true if it is not empty
            if(! checkField(field.name) {

                // add to array if invalid
               invalidFieldsArray.add(field.name);
            }
        }
    }
return invalidFieldsArray;
}    
​

http://jsfiddle.net/6Y69Q/2/

\$\endgroup\$
3
  • \$\begingroup\$ You should post the code here in the answer, too. \$\endgroup\$
    – ANeves
    Apr 3, 2012 at 8:31
  • \$\begingroup\$ Tejesh thank you for posting this. I think that I am following the logic of your example but I keep getting confused when I try to start writing. Do I have this logic correct? In the first part I am creating an array that I add all of the fields into. Then I have the email validation function, then the function that checks all fields for values, the function that actually check the form to see if it passes validation. If it finds invalid fields then it adds those fields into the invalidFieldsArray. But I am not sure how the invalidFieldsArray and invalidFields relate to each other? \$\endgroup\$
    – Judah
    Apr 5, 2012 at 21:55
  • \$\begingroup\$ added comments to code, see if it is clear now. \$\endgroup\$ Apr 6, 2012 at 9:12
0
\$\begingroup\$

If I'd have control over HTML I'd go the data- attribute way. Pretty much the same as ASP.NET MVC unobtrusive client side validation does (can't find source though).

In general each form field would have it's own data-validation-type and data-validation-message attributes.
data-validation-type attribute would define what data (number, positive number, email, text) could be filled into field. Appropriate validation function would be executed on field's value depending on attribute value.
data-validation-message would contain a message to be shown when field validation fails.
There could also be other attributes like data-validation-required.

Then in javascript you should:
- write validation function for each data type
- write one general function to gather all form fields with data-validation-* attribute and execute appropriate validation function.

This should cover most basic validation scenarios.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.