Search code examples
javascripthtmlajaxformsvanilla-forums

how to validate form data, then send via AJAX, then show the submitted results on the same page


I am setting up a simple one-page form website. I am having trouble with my validation working along with my AJAX request and hiding/showing the submitted form results. Here are my issues:

  1. When I click the Begin button to open the Registration Form, the JS validation is already triggered causing all the error messages to appear. I need the "Begin" button to only open the form and not trigger the JS validation.
  2. The validation is not working completely. The error codes are being presented, however, if you click the Register button with error messages (invalid inputs) the form will still submit. I need the form to not submit if there are any error messages.
  3. When I click the registration button, the page is still loading despite my use of the event.preventDefault() function. I need the Registration button to send the data if there are no errors, not reload the page, and hide the registration form to then show the div of the submitted data (I have not included the Submitted data Div in this code).

Note: I am using vanilla JS - AJAX and PHP

window.addEventListener('DOMContentLoaded', (event) => {

  // Open the Registration Form
  document.getElementById("beginButton").addEventListener("click", function() {
    document.body.classList.remove("begin");
  })


  window.addEventListener("load", function(event) {
    let fnameValid = fnameVerify();
    let lnameValid = lnameVerify();
    let emailValid = emailVerify();
    let dateOfBirthValid = dateOfBirthVerify();
    let nationOfOriginValid = nationOfOriginVerify();

    if (!(fnameValid && lnameValid && emailValid && dateOfBirthValid && nationOfOriginValid)) {
      event.preventDefault();
    } else {

      function sendData() {
        const XHR = new XMLHttpRequest();

        // Bind the FormData object and the form element
        const FD = new FormData(form);

        // Define what happens on successful data submission
        XHR.addEventListener("load", function(event) {
          alert(event.target.responseText);
        });

        // Define what happens in case of error
        XHR.addEventListener("error", function(event) {
          alert('Oops! Something went wrong.');
        });

        // Set up our request
        XHR.open("POST", "validate.php");

        // The data sent is what the user provided in the form
        XHR.send(FD);
      }

      // Access the form element...
      let form = document.getElementById("registrationForm");

      // ...and take over its submit event.
      form.addEventListener("submit", function(event) {
        event.preventDefault();
        sendData();
      });
      document.getElementById("registrationForm").addEventListener("submit")
      document.getElementById("beginButtonDiv").classList.add("hide");
      document.getElementById("registrationFormDiv").classList.add("hide");
      document.getElementById("serverMessageDiv").classList.add("hide");
      console.log("Success changing divs!");
    }
  });

  // RegEx Synteax
  const nameFormat = /^[a-zA-Z ]+$/;
  const emailFormat = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/;
  const dateFormat = /^\d{4}[\-\/\s]?((((0[13578])|(1[02]))[\-\/\s]?(([0-2][0-9])|(3[01])))|(((0[469])|(11))[\-\/\s]?(([0-2][0-9])|(30)))|(02[\-\/\s]?[0-2][0-9]))$/;

  // Event Hanlder Functions
  let firstName = document.getElementById("fname");
  let lastName = document.getElementById("lname");
  let email = document.getElementById("email");
  let dateOfBirth = document.getElementById('dateOfBirth');
  let nationOfOrigin = document.getElementById("nationOfOrigin");

  // Event Listeners for Error Messages '*'
  firstName.addEventListener("keyup", fnameVerify);
  lastName.addEventListener("keyup", lnameVerify);
  email.addEventListener("keyup", emailVerify);
  dateOfBirth.addEventListener("keyup", dateOfBirthVerify);
  nationOfOrigin.addEventListener("keyup", nationOfOriginVerify);

  // First Name Validation
  function fnameVerify() {
    let fname = document.forms["registrationForm"]["firstname"];
    let fnameErr = document.getElementById("fnameErr");

    // TODO: Split up the RegEx validation into min letters and only letters

    let error = "";
    if (fname.value == "") {
      error = " is required";
    } else if (!fname.value.match(nameFormat)) {
      error = " only letters";
    } else if (fname.value.length < 3) {
      error = " 3 letters min";
    } else if (fname.value.length > 45) {
      error = " 45 letters max";
    }

    if (error != "") {
      fname.classList.add("invalid");
      fnameErr.innerHTML = "*" + error;
      return false;
    } else {
      fname.classList.remove("invalid");
      fnameErr.innerHTML = "*";
      return true;
    }
  }


  // Last Name Validation
  function lnameVerify() {
    let lname = document.forms["registrationForm"]["lastname"];
    let lnameErr = document.getElementById("lnameErr");

    let error = "";
    if (lname.value == "") {
      error = " is required";
    } else if (!lname.value.match(nameFormat)) {
      error = " only letters";
    } else if (lname.value.length < 3) {
      error = " 3 letters min";
    } else if (lname.value.length > 45) {
      error = " 45 letters max";
    }

    if (error != "") {
      lname.classList.add("invalid");
      lnameErr.innerHTML = "*" + error;
      return false;
    } else {
      lname.classList.remove("invalid");
      lnameErr.innerHTML = "*";
      return true;
    }
  }

  // Email Validation
  function emailVerify() {
    let email = document.forms["registrationForm"]["email"];
    let emailErr = document.getElementById("emailErr");

    let error = "";
    if (email.value == "") {
      error = " is required";
    } else if (!email.value.match(emailFormat)) {
      error = " invalid email format";
    }

    if (error != "") {
      email.classList.add("invalid");
      emailErr.innerHTML = "*" + error;
      return false;
    } else {
      email.classList.remove("invalid");
      emailErr.innerHTML = "*";
      return true;
    }
  }

  // Date of Birth Validation
  function dateOfBirthVerify() {
    let dateOfBirth = document.forms["registrationForm"]["dateOfBirth"];
    let dateOfBirthErr = document.getElementById("dateOfBirthErr");

    let error = "";
    if (dateOfBirth.value == "") {
      error = " is required";
    } else if (!dateOfBirth.value.match(dateFormat)) {
      error = " invalid date";
    }

    if (error != "") {
      dateOfBirth.classList.add("invalid");
      dateOfBirthErr.innerHTML = "*" + error;
      return false;
    } else {
      dateOfBirth.classList.remove("invalid");
      dateOfBirthErr.innerHTML = "*";
      return true;
    }
  }

  // Nation of Origin Validation
  function nationOfOriginVerify() {
    let nationOfOrigin = document.forms["registrationForm"]["nationOfOrigin"];
    let nationOfOriginErr = document.getElementById("nationOfOriginErr");

    let error = "";
    if (nationOfOrigin.value == "") {
      error = " is required";
    } else if (nationOfOrigin.value.match("000")) {
      error = " select a country";
    }

    if (error != "") {
      nationOfOrigin.classList.add("invalid");
      nationOfOriginErr.innerHTML = "*" + error;
      return false;
    } else {
      nationOfOrigin.classList.remove("invalid");
      nationOfOriginErr.innerHTML = "*";
      return true;
    }
  }
});
/* Hiding the "Begin" button and showing the Registration form */

body.begin #registerFormDiv,
body:not(.begin) #serverMessageDiv,
body:not(.begin) #beginButtonDiv {
  display: none;
}


/* Hide class for hiding the register form and begin button upon form submission */

.hide {
  display: none;
}
<!-- Begin Button Div -->
<div id="beginButtonDiv">
  <button id="beginButton" class="buttonRise">BEGIN</button>
</div>

<!-- Regirstration Form Div -->
<div id="registerFormDiv">
  <form name="registrationForm" id="registrationForm" method="POST">

    <!-- Required Fields -->
    <span id="required" class="error">* All fields are required</span>
    <br><br>

    <div id="fullname">
      <!-- Fullname Labels & Errors -->
      <div id="fullnameLabels">
        <!-- First Name -->
        <div>
          <label id="firstLabel" for="fname">First Name</label>
          <span id="fnameErr" class="error">*</span>
        </div>
        <!-- Last Name -->
        <div>
          <label id="lastLabel" for="lname">Last Name</label>
          <span id="lnameErr" class="error">*</span>
        </div>
      </div>

      <!-- Fullname Inputs -->
      <div id="fullnameInputs">
        <input type="text" id="fname" name="firstname" placeholder="e.g. Reggie" />
        <input type="text" id="lname" name="lastname" placeholder="e.g. Rocket" />
      </div>
    </div>

    <!-- Email -->
    <label for="email">Email</label>
    <span id="emailErr" class="error">*</span>
    <br>
    <input type="email" id="email" name="email" placeholder="[email protected]" />

    <!-- Date of Birth -->
    <label for="dateOfBirth">Date of Birth</label>
    <span id="dateOfBirthErr" class="error">*</span>
    <br>
    <input type="date" id="dateOfBirth" name="dateOfBirth" placeholder="<?php echo date('Y-m-d'); ?>" max="5000-12-31" min="1900-01-01" />

    <!-- Nation of Origin -->
    <label for="nationOfOrigin">Nation of Origin</label>
    <span id="nationOfOriginErr" class="error">*</span>
    <br>
    <select id="nationOfOrigin" name="nationOfOrigin">
      <option value="000">--Select--</option>
      <option value="AF">Afghanistan</option>
    </select>

    <!-- Submit Button -->
    <input type="submit" class="buttonRise" value="Register" id="submitButton" name="submitButton">

  </form>
</div>

Any help on these three issues is much appreciated!!!


Solution

    1. The initial errors occur because you validate all your fields inside the load event on the window. My guess is that you want to move all of that logic into the submit event listener. Because you would want to only send the data is all the fields are valid, right? So remove the load event handler and replace it with a submit event listener for the form that you are submitting.
    2. See (1)
    3. Also see (1)

    Consider modifying your code the the following structure. It keeps the function definitions on the same level to prevent unexpected behavior, like not defining functions within a load event listener callback.

    You should validate your form when someone submits. Thats the moment everything, should be, filled in by the user. If the validation is successful, send the data. If not, show an error.

    I hope this gets you in the right direction.

    window.addEventListener('DOMContentLoaded', function() {
    
      beginButton.addEventListener('click', function() {
        // Open form logic.
      });
    
      function validateForm(form) {
        // Validation logic of all fields in form.
        // Return a true or false.
      }
    
      function sendData(form) {
        // XHR logic, sends the data in the form.
      }
    
      form.addEventListener('submit', function(event) {
        event.preventDefault();
        // Validate fields.
        if (validateForm(form)) {
          // If good, send. 
          sendData(form);
        }    
      });
    
    });