Error messages for form validation not appearing

Viewed 250

I am currently building a window on a website where users can book a boat trip, which requires multiple steps, and 3/5 steps include forms (I only included the first form in the html since it would get too long otherwise - see below).

I am currently handling the validation of the first form, which you can see below (".availability step1"). I've spent quite some time on this validation, however, I can't seem to figure out how to make only the "empty", so the fields that are not valid, take on the error message (.error). Right now it is recognising the ones that are invalid, and I'm getting the CSS connected to invalid (I am getting the red border around the input field), however, I am not getting through the html tag, which is a paragraph that goes underneath the input field.

function init() {
    setUpBooking();
}

function setUpBooking(){
    formValidation();
}

function formValidation() {
    /* ------------ form & elements ----------- */
    const form1 = document.querySelector(".availability");
    window.form1 = form1;
    const elements = form1.elements;
    window.elements = elements;

    /* --------- delete default validation ------- */
    form1.setAttribute("novalidate", true);

    /* ------------ custom validation ------------ */
    document.querySelector(".next").addEventListener("click", (e) => {
    e.preventDefault();

    // 1. select all inputs
    const formElements = form1.querySelectorAll("input, select");

    /* ------------ date ------------ */
    if (form1.checkValidity()) {
        console.log("form is valid");
        
        // loop through form elements and check if are valid or not
        formElements.forEach((el) => {
            if (el.checkValidity()) { 
                el.classList.add("valid");
            }

            // enable "next" btn when form is valid
            var counter = 1, step = "step";
            step = ".step" + counter;
            if (counter <= 5) {
                document.querySelector(step).classList.add("show");
            }
            counter++;
            if (counter > 5) {
                counter = 5;
            }
            step = ".step" + counter; // step is the class and we are appending counter with step so that it looks like the same class in the given class(like counter 1 means step1)

            document.querySelector(step).classList.remove("show");

            // enable "previous" btn when form is valid
            document.querySelector(".previous").addEventListener('click', function () {

                if (counter > 1) { // we don't want to remove the first step, it will always be shown
                    step = ".step" + counter;
            
                    document.querySelector(step).classList.add("show");
                }
                counter--;
                
                if (counter < 1) {
                    counter = 1;
                }
                step = ".step" + counter;
            
                document.querySelector(step).classList.remove("show");
            });
        });
    } else {
        formElements.forEach((el) => {
            
            if (!el.checkValidity()) {
                console.log("form is invalid");

                    el.classList.add("invalid");

                    document.querySelector(".error").style.display = "block";
                } else {
                    el.classList.remove("invalid");
                }
            })
        }
    })
}
.valid {
  border: 1px solid green;
}

.invalid {
  border: 1px solid red;
  border-top-left-radius: 3px;
  border-top-right-radius: 3px;
}

.error {
  text-transform: initial;
  margin-bottom: 20px;
  margin-top: -1px;
  border: 1px solid red;
  padding: 4px;
  z-index: 10;
  border-bottom-left-radius: 3px;
  border-bottom-right-radius: 3px;
  display: none;
}
<!-- AVAILABILITY -->
<form class="availability step1">
  <label for="date">Choose a date
    <input type="date" required>
      <p class="error date-err">Please pick a date for your tour</p>
  <label for="number">Choose passengers
    <input type="number" required>
      <p class="error passengers-err">Please pick a number of passengers</p>
  </label>

  <!-- PERSONAL DATA -->
  <form class="personalData step2">
  </form>

  <!-- ORDER OVERVIEW -->
  <div class="orderOverview step3">
  </div>

  <!-- PAYMENT -->
  <form class="payment step4">
  </form>

  <!-- buttons -->
  <button class="previous hide">Previous</button>
  <button class="next">Next</button>

1 Answers

Firstly, sorry. I've made some modifications to your forms.

Ideas are as follows:

  1. Appended a span field in every form.
  2. Before going to the next form just check every field is filled in the current form by passing the form number to the validateForm function and check all its input fields are filled.
  3. If yes, return true else return false.

Have a look at the snippet below:

function validateForm(step) {

    // console.log(document.forms[step - 1].elements);

    var i, l = document.forms[step - 1].elements.length;

    for (i = 0; i < l; i++) {
        // console.log(document.forms[step - 1].elements[i].value);
        if (!document.forms[step - 1].elements[i].value) {
            // console.log("All fields should be filled");
            document.getElementById("error" + step).textContent = "Fill all the fields please";
            document.getElementById("error" + step).style.color = "red";
            return false;
        }
    }
    document.getElementById("error" + step).textContent = "Form is completed";
    document.getElementById("error" + step).style.color = "green";
    return true;
}

var counter = 1,
    step = "step";

document.querySelector(".next").addEventListener('click', function() {

    step = ".step" + counter;

    if (validateForm(counter)) {

        if (counter <= 5) {
            document.querySelector(step).classList.add("show");
        }

        counter++;

        if (counter > 5) {
            counter = 5;
        }

        step = ".step" + counter; // step is the class and we are appending counter with step so that it looks like the same class in the given class(like counter 1 means step1)
        //console.log(step);

        document.querySelector(step).classList.remove("show");

    }
});

document.querySelector(".previous").addEventListener('click', function() {

    if (counter > 1) { // we don't want to remove the first step, it will always be shown
        step = ".step" + counter;
        //console.log(step);

        document.querySelector(step).classList.add("show");
    }

    counter--;

    if (counter < 1) {
        counter = 1;
    }


    step = ".step" + counter;

    document.querySelector(step).classList.remove("show");

});
.show {
    display: none;
}
<!-- AVAILABILITY -->
<form name="availability" class="availability step1">
    <h1>Step1</h1>
    <label for="date">Choose a date</label>
    <input type="date" name="DATE" required>
    <label for="firstname">Enter a firstname</label>
    <input type="text" name="FIRSTNAME" required>
    <br/>
    <span id="error1"> </span>
</form>

<!-- PERSONAL DATA -->
<form class="personalData step2 show">
    <h1>Step2</h1>
    <label for="date">Choose a date</label>
    <input type="date" name="DATE" required>
    <label for="firstname">Enter a firstname</label>
    <input type="text" name="FIRSTNAME" required>
    <br/>
    <span id="error2"></span>
</form>

<!-- ORDER OVERVIEW -->
<div class="orderOverview step3 show">
    <h1>Step3</h1>
    <label for="date">Choose a date</label>
    <input type="date" name="DATE" required>
    <label for="firstname">Enter a firstname</label>
    <input type="text" name="FIRSTNAME" required>
    <br/>
    <span id="error3"></span>
</div>

<!-- PAYMENT -->
<form class="payment step4 show">
    <h1>Step4</h1>
    <label for="date">Choose a date</label>
    <input type="date" name="DATE" required>
    <label for="firstname">Enter a firstname</label>
    <input type="text" name="FIRSTNAME" required>
    <br/>
    <span id="error4"></span>
</form>

<!-- buttons -->
<button class="previous hide">Previous</button>
<button class="next">Next</button>

Related