Am I over complicating my form validation?

Am I over complicating my form validation?

I am trying to make my booking form a little more user friendly... I have three sections...

  • First is a first/last name, email and phone number.
  • Second is a calendar to pick your date
  • Finally there is a dropdown select that shows a list of different time slots that are available.

It looks like this: 

I am using tzjs to get the users time zone, and I am using moment.js to compare dates and times.



The reason this form is complex is because I am only showing dates and times that are one hour in the future of that users time zone.


I am auto detecting the time zone and also ding some animations, for example if the user selects a date without putting in their personal details they will be scrolled up to the first section and the title will turn red and 'shake'.


Q: I am wondering if my code is inefficient and all over the place.


  1. $(function(){

        persistInput();

        var timezone = jstz.determine();     // get users timezone string
        $('#timeZone').val(timezone.name()); // set the name in the hidden form

        var date   = new Date();
        var offset = -date.getTimezoneOffset() + 60; // get users timezone offset (plus 60 minutes)

        /**
         * if serverside validation fails, the user doesn't lose the date that they have chosen
         */
        function persistInput(){
            if(okStepTwo()){
                days = document.getElementsByClassName('day'); // get array of .day classes
                for(i = 0; i < days.length; i++){ // foreach element check if its data attribute is before today using the users timezone offset
                    var startDate = $('#startDate').val();
                    if ($(days[i]).data('date') == startDate) {
                        $('#showStartDate').html(startDate);
                        $(days[i]).addClass('day-selected'); // if it is change its class to disabled
                    }
                }
            }
        }

        /**
         * validate step-1 (about you)
         */
        $('#firstName, #lastName, #email, #phone').change(function () {

            var a = $('#firstName').val();
            var b = $('#lastName').val();
            var c = $('#email').val();
            var d = $('#phone').val();

            if (a == '', b == '', c == '', d == ''){
                return false;
            }

            $("#stepOne").removeClass('text-danger').addClass('text-success');
            validate();
        });

        days = document.getElementsByClassName('day'); // get array of .day classes
        for(i = 0; i < days.length; i++){ // foreach element check if its data attribute is before today using the users timezone offset
            if (validateDate($(days[i]).data('date')) == false) {
                $(days[i]).addClass('day-expired'); // if it is change its class to disabled
            } else {
                $(days[i]).addClass('day-active'); // else make it selectable
            }
        }

        /**
         * check if a date is in the past
         * @param date string
         */
        function validateDate(thisDate) {

            var dateToday    = moment().utcOffset(offset);
            var selectedDate = moment(thisDate, ['YYYY-MM-DD']);

            var dateToday    = dateToday.format('YYYY-MM-DD');
            var selectedDate = selectedDate.format('YYYY-MM-DD');

            var dateToday    = moment(dateToday, ['YYYY-MM-DD']);
            var selectedDate = moment(selectedDate, ['YYYY-MM-DD']);

            if (selectedDate.isBefore(dateToday, 'day')) {
                return false;
            }
            return true;
        }

        /**
         * get the date (step-2)
         * @TODO: disable dates in the past according to a users time zone
         */
        $('.day-active').click(function(){
            var date = $(this).data('date'); // get the date attribute
            $('.day-active').removeClass('day-selected'); // remove the selected class from all elements
            $(this).addClass('day-selected'); // and apply it to just this element
            $('#showStartDate').html(date); // show the selected date to the user
            $('#startDate').val(date); // and put it in the hidden form
            $('#stepTwo').removeClass('text-danger').addClass('text-success'); // make header green
            filterTimeSlots();
            validate();
        });

        /**
         * filters out time slots that are in the past
         */
        function filterTimeSlots(){
            timeSlots = document.getElementsByClassName('time-slot'); // get array of .day classes
            for(i = 0; i < timeSlots.length; i++){ // foreach element check if its data attribute is before today using the users timezone offset
                if (validateTime($(timeSlots[i]).val()) == false) { // hide expired timeslots
                    $(timeSlots[i]).hide(); // if it is change its class to disabled
                } else {
                    $(timeSlots[i]).show(); // else make sure it's visible
                }
            }
        }

        /**
         * validate start time
         */
        function validateTime(timeSlot){

            date = $('#startDate').val();
            var selected_datetime = date + ' ' + timeSlot;
            var current_datetime = moment().utcOffset(offset).format('YYYY-MM-DD HH:mm A');

            var selectedDateTime = moment(selected_datetime, ["YYYY-MM-DD HH:mm A"]).utcOffset(offset);
            var currentDateTime = moment(current_datetime, ["YYYY-MM-DD HH:mm A"]).utcOffset(offset);

            if (selectedDateTime.isBefore(currentDateTime, 'minute')) {
                return false;
            }
            return true;
        }

        /**
         * step-3 (start time)
         */
        $("#getStartTime").on('change', function() {
            $("#showStartTime").html(this.value);
            $("#startTime").val(this.value);
            $('#stepThree').removeClass('text-danger').addClass('text-success');
            validate();
        });

        /**
         *
         */
        $('#submitButton').click(function(){
            validate();
        });

        /**
         * validate everything
         */
        function validate(){
            if(okStepOne()){
                if(okStepTwo()){
                    if(okStepThree()){
                        $('#submitButton').attr('type', 'submit').removeClass('disabled').addClass('btn-primary-cta animated shake');
                        $('html, body').animate({ // scroll to step one and shake
                            scrollTop: $("#submitButton").offset().top - 100,
                        }, 300);
                    } else {
                        // $('#stepThree').addClass('animated shake text-danger');
                    }
                } else {
                }
            } else { // show scroll to step one and shake
                if(okStepTwo()){
                } else {
                    if(okStepThree()){
                    } else {
                        $('#stepThree').addClass('animated shake text-danger')
                    }
                    $('#stepTwo').addClass('animated shake text-danger')
                }
                $('html, body').animate({ // scroll to step one and shake
                    scrollTop: $("#sectionOne").offset().top - 100,
                }, 300);
                $('#stepOne').addClass('animated shake text-danger');
            }
        }
        /**
         * check if there are values in the user details page
         */
        function okStepOne() {
            var a = $('#firstName').val();
            var b = $('#lastName').val();
            var c = $('#email').val();
            var d = $('#phone').val();

            if (a == '', b == '', c == '', d == ''){
                return false;
            }
            return true;
        }

        /**
         * check if there is a selected start date
         */
        function okStepTwo(){
            if($('#startDate').val() !== ''){
                return true;
            }
            return false;
        }

        /**
         * check if there is a selected start time
         */
        function okStepThree(){
            if($('#startTime').val() !== ''){
                return true;
            }
            return false;
        }
    });

Here is my HTML Markup...

  1. <div class="container padding-section-large">

        <!-- progress bar -->
        <div class="row padding-angled-small">
            <div class="col-md-8 col-md-offset-2">
                <ul class="progressbar progressbarfree">
                    <li class="active">
                        <?php echo $this->lang->line('progress_bar_select_course'); ?>
                    </li>
                    <li>
                        <?php echo $this->lang->line('progress_bar_pick_date'); ?>
                    </li>
                    <li>
                        <?php echo $this->lang->line('progress_bar_success'); ?>
                    </li>
                </ul>
            </div>
        </div>
        <!-- end progress bar -->

        <!-- course details -->
        <div class="row blurb-box">

            <div class="col-md-8">
                <h1 class="heading-border-left">
                    <?php echo $this->lang->line('book_evaluation_title'); ?>
                </h1>
                <h4>
                    <?php echo $this->lang->line('book_evaluation_description'); ?>
                </h4>
                <p class="footnote">
                    <?php echo $this->lang->line('book_course_what_you_need'); ?>
                </p>
                <br>
                <img alt="" src="<?php echo base_url('Public/images/frontend/book/english-certificates.png'); ?>" class="img-responsive">
            </div>

            <div class="col-md-4">
                <h3>
                    <?php echo $this->lang->line('book_evaluation_cost'); ?>
                    <?php if ($option->discount_percent != 0) : ?>
                        <span class="brand-color">
                            <b>(-<?php echo $option->discount_percent; ?>%)</b>
                        </span>
                    <?php endif; ?>
                </h3>

                <table class="table">
                    <tbody>
                        <tr>
                            <td>
                                <i class="fa fa-check brand-color"></i>
                                <?php echo $option->duration; ?>
                                <?php echo $this->lang->line('book_evaluation_minutes'); ?>
                            </td>
                        </tr>
                        <tr>
                            <td>
                                <i class="fa fa-check brand-color"></i>
                                <?php echo $this->lang->line('book_qualified_teacher'); ?>
                            </td>
                        </tr>
                        <tr>
                            <td>
                                <i class="fa fa-check brand-color"></i>
                                <?php echo $this->lang->line('book_materials_provided'); ?>
                            </td>
                        </tr>
                    </tbody>
                </table>
                <br>
                <h2 class="text-center text-success">
                    <?php echo $this->lang->line('book_evaluation_free'); ?>
                </h2>
            </div>
        </div>
        <!-- end course details -->

        <!-- personal details -->
        <div class="row padding-section-large" id="sectionOne">
            <div class="col-md-4 col-md-offset-4">

                <h3 id="stepOne">
                    <i class="fa fa-user"></i>
                    <?php echo $this->lang->line('book_step_one'); ?>
                </h3>

                <div class="row">
                    <div class="col-md-6">
                        <div class="form-group">
                            <?php echo (form_error('first_name')) ? form_error('first_name') : '' ?>
                            <input class="form-control frontend-form" id="firstName" form="theForm" type="text" name="first_name" value="<?php echo set_value('first_name'); ?>" placeholder="<?php echo $this->lang->line('form_first_name'); ?>">
                        </div>
                    </div>
                    <div class="col-md-6">
                        <div class="form-group">
                            <?php echo (form_error('last_name')) ? form_error('last_name') : '' ?>
                            <input class="form-control frontend-form" id="lastName" form="theForm" type="text" name="last_name" value="<?php echo set_value('last_name'); ?>" placeholder="<?php echo $this->lang->line('form_last_name'); ?>">
                        </div>
                    </div>
                </div>
                <div class="form-group">
                    <?php echo (form_error('email')) ? form_error('email') : '' ?>
                    <input class="form-control frontend-form" id="email" form="theForm" type="email" name="email" value="<?php echo set_value('email'); ?>" placeholder="<?php echo $this->lang->line('form_email'); ?>">
                </div>
                <div class="form-group">
                    <?php echo (form_error('phone')) ? form_error('phone') : '' ?>
                    <input class="form-control frontend-form" id="phone" form="theForm" type="tel" name="phone" value="<?php echo set_value('phone'); ?>" placeholder="<?php echo $this->lang->line('form_phone'); ?>">
                </div>
                <div class="checkbox">
                    <label>
                        <?php echo (form_error('terms')) ? form_error('terms') : '' ?>
                        <input form="theForm" type="checkbox" name="terms" value="1">
                        <?php echo $this->lang->line('book_terms_one'); ?>
                        <a target="_blank" href="<?php echo base_url('terms'); ?>">
                            <?php echo $this->lang->line('book_terms_two'); ?>
                        </a>
                    </label>
                </div>
            </div>
        </div>
        <!-- end personal details -->

        <!-- three calendars -->
        <div class="row padding-section-small">
            <div class="col-md-8 col-md-offset-2">

                <?php echo (form_error('start_time')) ? form_error('start_date') : '' ?>

                <h3 id="stepTwo">
                    <i class="fa fa-calendar"></i>
                    <?php echo $this->lang->line('book_step_two'); ?>
                </h3>

                <div class="row">
                    <div class="col-md-4">
                        <!-- calendar one -->
                        <?php echo $cal_one; ?>
                    </div>
                    <div class="col-md-4">
                        <!-- calendar two -->
                        <?php echo $cal_two; ?>
                    </div>
                    <div class="col-md-4">
                        <!-- calendar three -->
                        <?php echo $cal_three; ?>
                    </div>
                </div>
            </div>
        </div>
        <!-- end three calendars -->

        <!-- select time -->
        <div class="row padding-section-large">
            <div class="col-md-4 col-md-offset-4">

                <?php echo (form_error('start_date')) ? form_error('start_time') : '' ?>

                <h3 id="stepThree">
                    <i class="fa fa-clock-o"></i>
                    <?php echo $this->lang->line('book_step_three'); ?>
                </h3>

                <?php echo (form_error('start_time')) ? form_error('start_time') : '' ?>

                <div class="form-group">
                    <select class="form-control pick-time" id="getStartTime">
                        <option></option>
                        <?php foreach ($slots as $seconds => $time) : ?>
                            <option class="time-slot" value="<?php echo $time; ?>"><?php echo $time; ?></option>
                        <?php endforeach; ?>
                    </select>
                </div>

            </div>
        </div>
        <!-- end select time -->

        <!-- start show selected options -->
        <div class="row">
            <div class="col-md-6 col-md-offset-3">
                <h1 class="text-center">
                    <span id="showStartTime">--/-- --</span>
                </h1>
                <h3 class="text-center">
                    <span id="showStartDate">----/--/--</span>
                </h3>
            </div>
        </div>
        <!-- end show selected options -->

        <!-- submit button -->
        <div class="row">
            <div class="col-md-6 col-md-offset-3">
                <!-- start hidden form -->
                <form id="theForm" action="<?php echo base_url('book/free/' . $option->option_id); ?>" method="post">
                    <input id="timeZone" type="hidden" name="time_zone" value="<?php echo set_value('time_zone'); ?>">
                    <input id="startDate" type="hidden" name="start_date" value="<?php echo set_value('start_date'); ?>">
                    <input id="startTime" type="hidden" name="start_time" value="<?php echo set_value('start_time'); ?>">
                    <button id="submitButton" class="btn btn-block disabled" type="button">
                        <?php echo $this->lang->line('book_now'); ?>
                    </button>
                </form>
                <!-- end hidden form -->
            </div>
        </div>
        <!-- end submit button -->

    </div>

    <!-- external scripts -->
    <script src="<?php echo base_url('Public/js/custom/date-validation.js'); ?>"></script>
    <script src="<?php echo base_url('Public/js/moment/moment.js'); ?>"></script>
    <script src="<?php echo base_url('Public/js/jstz/jstz.min.js'); ?>"></script>

Sorry for so much code, not sure how else to ask for advice.


Many thanks in advance!