Search code examples
javascripthtmlvalidationpostjquery-ajax

JavaScript form (ajax submission) with validation doing something funky


I am trying to do a form validation function with Ajax submission. For some reason the validation doesn't work and when it submits, my server gets the empty fields (when I am testing for the validation) but it shows that it tried to post to the same page... I don't know why.

Form:

<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-BmbxuPwQa2lc/FVzBcNJ7UAyJxM6wuqIj61tLrc4wSX0szH/Ev+nYRRuWlolflfl" crossorigin="anonymous">
<form id='form' novalidate method="post" class='m-2 p-1'>
  <div class='row'>
    <div class='col p-1'>
      <div class="form-floating mb-3">
        <input required type="text" name='First Name' class="form-control" id="fname" placeholder="First Name">
        <label for="fname">First Name<span class='red' aria-label='required'> *</span></label>
      </div>
    </div>
    <div class='col p-1'>
      <div class="form-floating mb-3">
        <input required type="text" name='Last Name' class="form-control" id="lname" placeholder="Last Name">
        <label for="lname">Last Name</label>
      </div>
    </div>
  </div>
  <div class='row'>
    <div class='col p-1'>
      <div class="form-floating mb-3">
        <input required type="email" name='Email' class="form-control" id="email" placeholder="Email">
        <label for="lname">Email <span class='red' aria-label='required'> *</span></label>
      </div>
    </div>
    <div class='col p-1'>
      <div class="form-floating mb-3">
        <select required name='Reason For Contacting' class="form-control" id="reason" placeholder="Reason For Contacting">
          <option value='Feedback' selected>Feedback</option>
          <option value='other'>Other</option>
        </select>
        <label for="why">Reason For Contacting<span class='red' aria-label='required'> *</span></label>
      </div>
    </div>
  </div>
  <div class='row'>
    <div class='col p-1'>
      <div class="form-floating mb-3">
        <textarea required name='Comments' class="form-control" id="comment" placeholder="Your Comments"></textarea>
        <label for="comment">Your Comments<span class='red' aria-label='required'> *</span></label>
      </div>
    </div>
  </div>
  <div class='row'>
    <div class='col p-1'>
      <button class='form-control btn btn-outline-primary' id='submit'>Send</button>
    </div>
  </div>
</form>

My JS File:

$(document).ready(() => {
  autosize($('textarea'))
  $('#submit').click((e) => {
    if (validate() == true) {
      sendForm();
    } else {
      error(validate())
    }
  })
})
var errors;
window.onerror = function(msg, url, linenumber) {
  alert('Error message: ' + msg + '\nURL: ' + url + '\nLine Number: ' + linenumber);
  return true;
}

function validate() {
  elements = $(':input')
  elements.each((element) => {
    element = $(element).get()
    if (element.value === '' || !email(element)) {
      errors += element.name + " is invalid."
    } else {
      return;
    }
  })
  if (errors) {
    return errors
  } else true;
}

function sendForm() {
  name = $('input[name="First Name"]').val().trim() + " " + $('input[name="Last Name"]').val().trim()
  email = $('input[name="Email"]').val().trim()
  why = $("select").val().trim()
  comments = $('textarea').val().trim()
  data = {
    "name": name,
    "email": email,
    "reason": why,
    "text": comments
  }
  $.ajax({
    type: 'POST',
    url: 'https://admin.bekesbikes.tk/contact',
    crossDomain: true,
    data: data,
    dataType: 'json',
    success: (responseData, textStatus, errorThrown) => {
      new Notify({
        title: 'Submitted!',
        text: 'Your feedback has been recorded!\n\nWe will get back to your email shortly!\n\nHope to see you soon!',
        effect: 'slide',
        status: 'success',
        speed: 1000,
        autoclose: true
      })
      $(':input').val('');
      $('select').val('Feedback')
    },
    error: (responseData, textStatus, errorThrown) => {
      new Notify({
        title: 'Could not submit!',
        text: 'The form could not be submitted.\n\nPlease try again or come back later!\n\nSorry for the inconvenience.',
        effect: 'slide',
        customIcon: "<img src='https://www.flaticon.com/svg/vstatic/svg/753/753345.svg?token=exp=1616679486~hmac=4f66bb69b263e9e4d9be5038a16cc41d' width='50px'>",
        status: 'error',
        speed: 1000,
        autoclose: true
      })
    }
  });
}

function error(text) {
  new Notify({
    title: 'Form Fields Are Not Correct',
    text: text,
    effect: 'slide',
    status: 'info',
    speed: 1000,
    autoclose: true
  })
}

function send() {
  if (validate()) {
    sendForm()
  } else {
    error(validate())
  }
}

function email(element) {
  if (element.type === 'email' && /^[^\s@]+@[^\s@]+$/.text(element.value)) {
    return true;
  } else if (element.type !== 'email') {
    return true;
  } else {
    return false;
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

Where I go when I submit (the form is at this URL): Where I go when I submit (the form is at this URL):

Any Idea what I should do? I am using node.js with express.js.

I added: e.preventDefault() to my submit event handler but now when I submit the form without filling in anything, I get this notification:

enter image description here


Solution

  • I changed your click handler:

    • default prevention,
    • validate() as variable so that it runs only once,

    the errors declaration

    • empty string instead of undefined,

    your validate() function

    • excluded button using :not(),
    • changed arrow function to ordinary anonymous function,
    • used this instead of element, which was only an index,
    • added a return to the last else,

    and your email() function

    • sourced the email validation out to an own function.

    I also deleted send(), as it was not used, declared the variables in sendForm() with var and added many semicolons -> maybe in your code one is already missing and you are hoping that the js error correction will add them automatically...

    Finally i added the param showIcon to your Notify objects (that was the 'undefined' part ;)

    $(document).ready(() => {
    
      autosize($('textarea'))
        
        $('#form').submit((e) => {
            e.preventDefault();
            var validated = validate();
            if (validated == true) {
                sendForm();
            } else error(validated);
        });
        
        var errors = '';
    
        window.onerror = function(msg, url, linenumber) {
            alert('Error message: ' + msg + '\nURL: ' + url + '\nLine Number: ' + linenumber);
            return true;
        }
    
        function validate() {
            elements = $(':input:not(button)');
            elements.each(function() {
                if (this.value === '' || !email(this)) {
                    errors += this.name + " is invalid.";
                } else return;
            });
            if (errors) {
                return errors;
            } else return true;
        }
    
        function sendForm() {
            var name = $('input[name="First Name"]').val().trim() + " " + $('input[name="Last Name"]').val().trim();
            var email = $('input[name="Email"]').val().trim();
            var why = $("select").val().trim();
            var comments = $('textarea').val().trim();
            var data = {
                "name": name,
                "email": email,
                "reason": why,
                "text": comments
            };
            $.ajax({
                type: 'POST',
                url: 'https://admin.bekesbikes.tk/contact',
                crossDomain: true,
                data: data,
                dataType: 'json',
                success: (responseData, textStatus, jqXHR) => {
                    new Notify({
                        title: 'Submitted!',
                        text: 'Your feedback has been recorded!\n\nWe will get back to your email shortly!\n\nHope to see you soon!',
                        effect: 'slide',
                        status: 'success',
                        speed: 1000,
                        autoclose: true,
                        showIcon: false
                    });
                    $(':input').val('');
                    $('select').val('Feedback');
                },
                error: (jqXHR, textStatus, errorThrown) => {
                    new Notify({
                        title: 'Could not submit!',
                        text: 'The form could not be submitted.\n\nPlease try again or come back later!\n\nSorry for the inconvenience.',
                        effect: 'slide',
                        customIcon: "<img src='https://www.flaticon.com/svg/vstatic/svg/753/753345.svg?token=exp=1616679486~hmac=4f66bb69b263e9e4d9be5038a16cc41d' width='50px'>",
                        status: 'error',
                        speed: 1000,
                        autoclose: true,
                        showIcon: true
                    });
                }
            });
        }
    
        function error(text) {
            new Notify({
                title: 'Form Fields Are Not Correct',
                text: text,
                effect: 'slide',
                status: 'info',
                speed: 1000,
                autoclose: true,
                showIcon: false
            })
        }
    
        function validateEmail(email) {
            const 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(email);
        }
    
        function email(element) {
            if (element.type === 'email' && validateEmail(element.value)) {
                return true;
            } else if (element.type !== 'email') {
                return true;
            } else return false;
        }
        
    });