3
\$\begingroup\$

I am validating a form using jQuery.

It is working perfectly, but I just feel the code is quite "bulky". There is a lot of if statements being used to achieve this logic in the app.sendForm.init() function. I think this could be tidied and any advice here would be greatly appreciated. Perhaps I should be using a switch statement instead?

"use strict";
/*
create namespace to prevent 
cluttering of the global namespace
*/ 
var app = app || {};
(function(){

    app.initialize = {
        init: function() {
            app.sendForm.init();
        }
    };

    app.sendForm = {
        init: function(){    
            $("#entry").submit(function( event ) {
                var userEmail = $("#email"),
                    userName = $("#first_name"),
                    userLastName = $("#last_name"),
                    date = $("#birth_day"),
                    month = $("#birth_month"),
                    year = $("#birth_year"),
                    contestName = $("#contest1_name"),
                    countryName = $("#country"),
                    privacyCheck = $('#privacy_check');

                if (![contestName, date, month, year, countryName, userName, userLastName]
                    .every(app.validation.empty) || !app.validation.dateOfBirth(date, month, year) || !app.validation.email(userEmail) ) {
                    event.preventDefault();
                    alert("There are errors with your form.");
        
                    //set invalid class on form elements if errors
                    app.setInvalidClass.init(!app.validation.email(userEmail), userEmail);
                    app.setInvalidClass.init(!app.validation.empty(userName), userName);
                    app.setInvalidClass.init(!app.validation.empty(userLastName), userLastName);
                    app.setInvalidClass.init(!app.validation.empty(contestName), contestName);
                    app.setInvalidClass.init(!app.validation.empty(countryName), countryName);
                    app.setInvalidClass.init(!app.validation.empty(date), date);
                    app.setInvalidClass.init(!app.validation.empty(month), month);
                    app.setInvalidClass.init(!app.validation.empty(year), year);

                    //ternary operator to check if privacy box was checked
                    privacyCheck.css(privacyCheck.is(':checked') ?
                        { outline: 'none'} :
                        { outline: 'red solid thin'});

                } else {
                    alert("You have entered the competition.");
                }      
            });
        }
    };
     
    /*
     * Validation
     */
    app.validation = {
        
        //Validate email address.
        email: function(id) {
            var emailVal = id.val(),
                re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
            return re.test(emailVal);
        },

        //Check if value is empty.
        empty: function(id) {
            var elementVal = $.trim(id.val());
            if(elementVal.length > 0)
                return true;
        },

        //Check user's age.
        dateOfBirth: function(date, month, year) {
            var forbiddenAge = 14;
            var DOB = date.val() + " " + month.val() + " " + year.val();
            var today = new Date();
            var birthDate = new Date(DOB);
            var age = today.getFullYear() - birthDate.getFullYear();
            var m = today.getMonth() - birthDate.getMonth();
            if (m < 0 || (m === 0 && today.getDate() < birthDate.getDate())) {
                age--;
            }    
            if(age < forbiddenAge){
                alert("You are under 14. You are unable to enter the competition");
                return false;
            }
            else{
                return true;
            }
        }
    };

    app.setInvalidClass = {
        init: function (invalidCondition, jQueryObject) {
            if(invalidCondition) {
                jQueryObject.addClass('invalid');
            }
            else {
                jQueryObject.removeClass('invalid');
            }
        }
    };

    $(document).ready(app.initialize .init);

})(jQuery);
body {
    background-color: #fff;
    color: #000;
    font-family: 'Arial', sans-serif;
    margin: 0;
}


#entry {
    font-family: 'Arial', sans-serif;
    max-width: 400px;
    margin: 0 auto;
}

#entry input,
#entry select {
    display: block;
    margin-bottom: 10px;
}

#entry label {
    padding-bottom: 5px;
}

#entry #birth_day,
#entry #birth_month,
#entry #birth_year {
    display: inline-block;
}

#entry input[type=submit] {
    display: block;
    border: 1px solid #1e1e1e;
    text-transform: uppercase;
    font-family: 'Arial', sans-serif;
    font-size: 16px;
    font-weight: 400;
    text-transform: capitalize;
    text-decoration: none;
    color: #fff;
    line-height: 20px;
    letter-spacing: .5px;
    max-width: 150px;
    height: 40px;
    padding: 0 10px;
    background: #1e1e1e;
    text-shadow: none;
    box-shadow: none;
    -webkit-box-shadow: none;
    font-weight: 400;
    margin-top: 15px;
}

#privacy {
    font-size: 12px;
}

.invalid {
    border-color: #ed0000;
    background-color: #ffd8d8;
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <link rel="stylesheet" type="text/css" href="style.css">
    <!-- JQUERY CDN -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.2/jquery.min.js"></script>

    <!-- JAVASCRIPT -->
    <script src="script.js"></script>
</head>

<body>
    
    <noscript>
        For full functionality of this site it is necessary to enable JavaScript.
        Here are the <a href="http://www.enable-javascript.com/" target="_blank">
        instructions how to enable JavaScript in your web browser</a>.
    </noscript>

    <div>

        <form id="entry">

        <label for="first_name">First name:</label>
        <input id="first_name" type="text" name="first_name" />

        <label for="last_name">Last name:</label>
        <input id="last_name"  type="text" name="last_name" />

        <label>Country/Region</label>
        <select id="country" name="country">
            <option value="">Select Your Country/Region</option>
            <option value="GB">United Kingdom</option>
            <option value="AF">Afghanistan</option>
            <option value="AX">Aland Islands</option>
            <option value="AL">Albania</option>
            <option value="DZ">Algeria</option>
            <option value="AS">American Samoa</option>
            <option value="BO">Bolivia</option>
            <option value="BA">Bosnia and Herzegovina</option>
            <option value="BW">Botswana</option>
            <option value="BV">Bouvet island</option>
            <option value="BR">Brazil</option>
            <option value="IO">British Indian Ocean Territory</option>
            <option value="BI">Burundi</option>
            <option value="KH">Cambodia</option>
        </select>

        <label for="email">Email:</label>
        <input id="email" type="text" name="email" />

        <label>Date of Birth</label>
        <select id="birth_day" name="birth_day">
            <option value="">DD</option>
            <option value="1">1</option>
            <option value="2">2</option>
            <option value="3">3</option>
            <option value="4">4</option>
            <option value="5">5</option>
            <option value="6">6</option>
            <option value="7">7</option>
            <option value="8">8</option>
            <option value="9">9</option>
            <option value="10">10</option>
            <option value="11">11</option>
            <option value="12">12</option>
            <option value="13">13</option>
            <option value="14">14</option>
            <option value="15">15</option>
            <option value="16">16</option>
            <option value="17">17</option>
            <option value="18">18</option>
            <option value="19">19</option>
            <option value="20">20</option>
            <option value="21">21</option>
            <option value="22">22</option>
            <option value="23">23</option>
            <option value="24">24</option>
            <option value="25">25</option>
            <option value="26">26</option>
            <option value="27">27</option>
            <option value="28">28</option>
            <option value="29">29</option>
            <option value="30">30</option>
            <option value="31">31</option>
        </select>
        <select id="birth_month" name="birth_month">
            <option value="">MM</option>
            <option value="JAN">January</option>
            <option value="FEB">February</option>
            <option value="MAR">March</option>
            <option value="APR">April</option>
            <option value="MAY">May</option>
            <option value="JUN">June</option>
            <option value="JUL">July</option>
            <option value="AUG">August</option>
            <option value="SEP">September</option>
            <option value="OCT">October</option>
            <option value="NOV">November</option>
            <option value="DEC">December</option>
        </select>
        <select id="birth_year" name="birth_year">
            <option value="">YYYY</option>
            <option value="2007">2007</option>
            <option value="2006">2006</option>
            <option value="2005">2005</option>
            <option value="2004">2004</option>
            <option value="2003">2003</option>
            <option value="2002">2002</option>
            <option value="2001">2001</option>
            <option value="2000">2000</option>
            <option value="1999">1999</option>
            <option value="1998">1998</option>
            <option value="1997">1997</option>
            <option value="1996">1996</option>
            <option value="1995">1995</option>
            <option value="1994">1994</option>
            <option value="1993">1993</option>
            <option value="1992">1992</option>
            <option value="1991">1991</option>
            <option value="1990">1990</option>
            <option value="1989">1989</option>
            <option value="1988">1988</option>
            <option value="1987">1987</option>
            <option value="1986">1986</option>
            <option value="1985">1985</option>
            <option value="1984">1984</option>
            <option value="1983">1983</option>
            <option value="1982">1982</option>
            <option value="1981">1981</option>
            <option value="1980">1980</option>
            <option value="1979">1979</option>
            <option value="1978">1978</option>
            <option value="1977">1977</option>
            <option value="1976">1976</option>
        </select>
        <div id="privacy">
            <input id="privacy_check" type="checkbox" name="privacy_check" />
        
            <label for="privacy_check">I have read and understood the Terms and Conditions.</label>
        </div>
        <input type="submit" name="ch_access" value="Submit" />
        </form>
    </div>
</body>
</html>

\$\endgroup\$
8
  • 1
    \$\begingroup\$ i would advice use plugin jquery.validation. It is suitable in your case. For example date range stackoverflow.com/questions/3761185/jquery-validate-date-range \$\endgroup\$
    – user106408
    Commented May 26, 2016 at 11:48
  • \$\begingroup\$ What's the purpose of the app.docOnReady-object? Why not calling " $(document).ready( app.initialize.init() ) " directly? \$\endgroup\$ Commented May 27, 2016 at 7:46
  • \$\begingroup\$ Overall: There's a lot of nested objects. I don't think that's all necessary. Could be all simpler. \$\endgroup\$ Commented May 27, 2016 at 7:49
  • \$\begingroup\$ @st88 see updated js code. Could you elaborate on what you mean by too many nested objects in the updated code. Also, could you provide code which you feel is simpler? Do you not think the separation of each piece of functionality into a method is a nice way of organising the code? \$\endgroup\$
    – phantom
    Commented May 27, 2016 at 8:29
  • \$\begingroup\$ @phantom I meant: You had an object with a method. The method is called after the document is loaded. Then: The only purpose of the called method is to call the method of another object ... and so on. Nice separation? To be honest: Done in this way? No. It's just more exhausting to read. Harder to get an idea what the code is actually doing. \$\endgroup\$ Commented May 27, 2016 at 8:49

1 Answer 1

3
\$\begingroup\$

First of all: Very long lines are stressful for the eyes to follow. So using more line breaks would be nice.

Second: You got an error in your code. enter image description here

Third: I would structure it different.

Might not be the ideal way. It's just the way I would do it:

"use strict";
/*
create namespace to prevent 
cluttering of the global namespace
*/ 
var app = app || {};

app.validation = {
        
  //Validate email address.
  email: function(id) {
    var emailVal = id.val(),
        re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
    return re.test(emailVal);
  },

  //Check if value is empty.
  empty: function(id) {
    var elementVal = $.trim(id.val());
    if(elementVal.length > 0)
      return true;
  },

  //Check user's age.
  dateOfBirth: function(date, month, year) {
    var forbiddenAge = 14;
    var DOB = date.val() + " " + month.val() + " " + year.val();
    var today = new Date();
    var birthDate = new Date(DOB);
    var age = today.getFullYear() - birthDate.getFullYear();
    var m = today.getMonth() - birthDate.getMonth();
    if (m < 0 || (m === 0 && today.getDate() < birthDate.getDate())) {
      age--;
    }    
    if(age < forbiddenAge){
      alert("You are under 14. You are unable to enter the competition");
      return false;
    }
    else{
      return true;
    }
  }
};

// After the document is loaded: Attach the
//  validation logic to submit-event of the button.
$(function() {
  $("#entry").submit(function( event ) {
    var userEmail = $("#email"),
        userName = $("#first_name"),
        userLastName = $("#last_name"),
        date = $("#birth_day"),
        month = $("#birth_month"),
        year = $("#birth_year"),
        countryName = $("#country"),
        privacyCheck = $('#privacy_check');

    if(!app.validation.dateOfBirth(date, month, year) || 
       !app.validation.empty(date) ||
       !app.validation.empty(month) ||
       !app.validation.empty(year) || 
       !app.validation.empty(countryName) || 
       !app.validation.email(userEmail) || 
       !app.validation.empty(userName) || 
       !app.validation.empty(userLastName)){
      event.preventDefault();
      alert("There are errors with your form.");

      //set invalid class on form elements if errors
      app.setInvalidClass.init(!app.validation.email(userEmail), userEmail);
      app.setInvalidClass.init(!app.validation.empty(userName), userName);
      app.setInvalidClass.init(!app.validation.empty(userLastName), userLastName);
      app.setInvalidClass.init(!app.validation.empty(countryName), countryName);
      app.setInvalidClass.init(!app.validation.empty(date), date);
      app.setInvalidClass.init(!app.validation.empty(month), month);
      app.setInvalidClass.init(!app.validation.empty(year), year);

      //ternary operator to check if privacy box was checked
      privacyCheck.css(privacyCheck.is(':checked') ?
                       { outline: 'none'} :
                       { outline: 'red solid thin'});

    } else {
      alert("You have entered the competition.");
    }      
  });
})
body {
    background-color: #fff;
    color: #000;
    font-family: 'Arial', sans-serif;
    margin: 0;
}


#entry {
    font-family: 'Arial', sans-serif;
    max-width: 400px;
    margin: 0 auto;
}

#entry input,
#entry select {
    display: block;
    margin-bottom: 10px;
}

#entry label {
    padding-bottom: 5px;
}

#entry #birth_day,
#entry #birth_month,
#entry #birth_year {
    display: inline-block;
}

#entry input[type=submit] {
    display: block;
    border: 1px solid #1e1e1e;
    text-transform: uppercase;
    font-family: 'Arial', sans-serif;
    font-size: 16px;
    font-weight: 400;
    text-transform: capitalize;
    text-decoration: none;
    color: #fff;
    line-height: 20px;
    letter-spacing: .5px;
    max-width: 150px;
    height: 40px;
    padding: 0 10px;
    background: #1e1e1e;
    text-shadow: none;
    box-shadow: none;
    -webkit-box-shadow: none;
    font-weight: 400;
    margin-top: 15px;
}

#privacy {
    font-size: 12px;
}

.invalid {
    border-color: #ed0000;
    background-color: #ffd8d8;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<noscript>
  For full functionality of this site it is necessary to enable JavaScript.
  Here are the <a href="http://www.enable-javascript.com/" target="_blank">
  instructions how to enable JavaScript in your web browser</a>.
</noscript>

<div>

  <form id="entry">

    <label for="first_name">First name:</label>
    <input id="first_name" type="text" name="first_name" />

    <label for="last_name">Last name:</label>
    <input id="last_name"  type="text" name="last_name" />

    <label>Country/Region</label>
    <select id="country" name="country">
      <option value="">Select Your Country/Region</option>
      <option value="GB">United Kingdom</option>
      <option value="AF">Afghanistan</option>
      <option value="AX">Aland Islands</option>
      <option value="AL">Albania</option>
      <option value="DZ">Algeria</option>
      <option value="AS">American Samoa</option>
      <option value="BO">Bolivia</option>
      <option value="BA">Bosnia and Herzegovina</option>
      <option value="BW">Botswana</option>
      <option value="BV">Bouvet island</option>
      <option value="BR">Brazil</option>
      <option value="IO">British Indian Ocean Territory</option>
      <option value="BI">Burundi</option>
      <option value="KH">Cambodia</option>
    </select>

    <label for="email">Email:</label>
    <input id="email" type="text" name="email" />

    <label>Date of Birth</label>
    <select id="birth_day" name="birth_day">
      <option value="">DD</option>
      <option value="1">1</option>
      <option value="2">2</option>
      <option value="3">3</option>
      <option value="4">4</option>
      <option value="5">5</option>
      <option value="6">6</option>
      <option value="7">7</option>
      <option value="8">8</option>
      <option value="9">9</option>
      <option value="10">10</option>
      <option value="11">11</option>
      <option value="12">12</option>
      <option value="13">13</option>
      <option value="14">14</option>
      <option value="15">15</option>
      <option value="16">16</option>
      <option value="17">17</option>
      <option value="18">18</option>
      <option value="19">19</option>
      <option value="20">20</option>
      <option value="21">21</option>
      <option value="22">22</option>
      <option value="23">23</option>
      <option value="24">24</option>
      <option value="25">25</option>
      <option value="26">26</option>
      <option value="27">27</option>
      <option value="28">28</option>
      <option value="29">29</option>
      <option value="30">30</option>
      <option value="31">31</option>
    </select>
    <select id="birth_month" name="birth_month">
      <option value="">MM</option>
      <option value="JAN">January</option>
      <option value="FEB">February</option>
      <option value="MAR">March</option>
      <option value="APR">April</option>
      <option value="MAY">May</option>
      <option value="JUN">June</option>
      <option value="JUL">July</option>
      <option value="AUG">August</option>
      <option value="SEP">September</option>
      <option value="OCT">October</option>
      <option value="NOV">November</option>
      <option value="DEC">December</option>
    </select>
    <select id="birth_year" name="birth_year">
      <option value="">YYYY</option>
      <option value="2007">2007</option>
      <option value="2006">2006</option>
      <option value="2005">2005</option>
      <option value="2004">2004</option>
      <option value="2003">2003</option>
      <option value="2002">2002</option>
      <option value="2001">2001</option>
      <option value="2000">2000</option>
      <option value="1999">1999</option>
      <option value="1998">1998</option>
      <option value="1997">1997</option>
      <option value="1996">1996</option>
      <option value="1995">1995</option>
      <option value="1994">1994</option>
      <option value="1993">1993</option>
      <option value="1992">1992</option>
      <option value="1991">1991</option>
      <option value="1990">1990</option>
      <option value="1989">1989</option>
      <option value="1988">1988</option>
      <option value="1987">1987</option>
      <option value="1986">1986</option>
      <option value="1985">1985</option>
      <option value="1984">1984</option>
      <option value="1983">1983</option>
      <option value="1982">1982</option>
      <option value="1981">1981</option>
      <option value="1980">1980</option>
      <option value="1979">1979</option>
      <option value="1978">1978</option>
      <option value="1977">1977</option>
      <option value="1976">1976</option>
    </select>
    <div id="privacy">
      <input id="privacy_check" type="checkbox" name="privacy_check" />

      <label for="privacy_check">I have read and understood the Terms and Conditions.</label>
    </div>
    <input type="submit" name="ch_access" value="Submit" />
  </form>
</div>

\$\endgroup\$
2
  • \$\begingroup\$ thanks @st88. so are you just moving the validation to the top of the file? \$\endgroup\$
    – phantom
    Commented May 27, 2016 at 9:45
  • \$\begingroup\$ @phantom Mmh, ... yes. These structure has proven alright for me: First variable-declarations, then second the function-declarations or -expressions. Then third attaching the functions to events. I should mention: I'm not deep into jQuery. If I write JavaScript then rather "Vanilla". \$\endgroup\$ Commented May 27, 2016 at 10:01

Your Answer

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

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