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\$
  • 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 May 26 '16 at 11:48
  • \$\begingroup\$ What's the purpose of the app.docOnReady-object? Why not calling " $(document).ready( app.initialize.init() ) " directly? \$\endgroup\$ – michael.zech May 27 '16 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\$ – michael.zech May 27 '16 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 May 27 '16 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\$ – michael.zech May 27 '16 at 8:49
2
\$\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\$
  • \$\begingroup\$ thanks @st88. so are you just moving the validation to the top of the file? \$\endgroup\$ – phantom May 27 '16 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\$ – michael.zech May 27 '16 at 10:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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