0

I have a text input field, where I want to display 2 error messages on eventListener "input", (as the user types).

  1. Display "Please enter a first name", if the field has not been completed.
  2. Only display "Please enter a valid first name", if the field has been completed/when the user is typing, but includes numbers, (when it shouldn't).

I've kind of got this half working.

And the problem I have, is that my validation isn't working properly.

If I enter valid text, my second error message appears. If I remove the valid text, both error messages appear.

I think the first error message is working fine.

I just only want the second error message to appear as the user types, (not when they have removed the text).

What's the best way to achieve this?

Thanks!

What's the best way to format logic like this, (using JavaScript only, not jQuery).

function checkFirstNameValidity(value) {
    return /^[^0-9+;:""`|!?<>().,\/\\@#$£%^&*]{1,30}$/.test(value);
};

const firstNameField = document.getElementById("n-form-first-name");
const nameError1 = document.getElementById("n-form-first-name-error-1");
const nameError2 = document.getElementById("n-form-first-name-error-2");

let isFirstNameFieldValid = "";
let isSecondNameFieldValid = "";

function validateFirstName(e) {
    e.preventDefault();
    isFirstNameFieldValid = true;

    if (!firstNameField.value) {
        // nameError.outerText = "Please enter a first name";
        nameError1.classList.add("visible");
        firstNameField.classList.add("invalid");
        nameError1.setAttribute("aria-hidden", false);
        nameError1.setAttribute("aria-invalid", true);
        return isFirstNameFieldValid = false;
    }

    else if (firstNameField.value && !checkFirstNameValidity.value) {
        // nameError2.outerText = "Please enter a valid first name";
        nameError2.classList.add("visible");
        firstNameField.classList.add("invalid");
        nameError2.setAttribute("aria-hidden", false);
        nameError2.setAttribute("aria-invalid", true);
        return isSecondNameFieldValid = false;
    }
    // return isFirstNameFieldValid;
};

function myFunction() {
    if (isFirstNameFieldValid === true) {
        console.log("isFirstNameFieldValid", isFirstNameFieldValid);
        nameError1.classList.remove("visible");
        firstNameField.classList.remove("invalid");
    } else {
        console.log("isFirstNameFieldValid", isFirstNameFieldValid);
    }

    if (isSecondNameFieldValid === true) {
        console.log("isSecondNameFieldValid", isSecondNameFieldValid);
        nameError2.classList.remove("visible");
        firstNameField.classList.remove("invalid");
    } else {
        console.log("isSecondNameFieldValid", isSecondNameFieldValid);
    }
};

firstNameField.addEventListener("input", validateFirstName);
/* First name */
#n-form-first-name-error-1, #n-form-first-name-error-2 {
    display: none;
    font-size: 0.8em;
  }

#n-form-first-name-error-1.visible  {
    display: block;
}

#n-form-first-name-error-2.visible  {
    display: block;
}

input[type=text].invalid {
    border-color: red;
}

input[type=text].valid {
    border-color: #f60;
}
    <form>
      <div class="n-form-booker-contact-details">
        <!-- Contact Fields -->
        <div class="n-form-details">
          <!-- First Name -->
          <input type="text" id="n-form-first-name" name="n-form-first-name" placeholder="First name" onfocusout="myFunction()" required>
          <label for="n-form-first-name">First name</label>
          <span class="error" id="n-form-first-name-error-1" aria-live="polite">Please enter a first name</span>
          <span class="error" id="n-form-first-name-error-2" aria-live="polite">Please enter a valid first name</span>
        </div>
    </form>
Reena Verma
  • 1,617
  • 2
  • 20
  • 47
  • Remove all javascript validation and use the [constraint validation api](https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Constraint_validation), you already have the `required` attribute so use it? you could add a pattern to limit the characters – Endless May 31 '21 at 16:23
  • @Endless - i don't want to use the HTML5 validation, as you can't stylise the error messages. So I need to user client-side javascript validation. – Reena Verma May 31 '21 at 16:25
  • 1
    I think it dose a better job at it then any JS validation out there. Sure you can't style it but it isn't that ugly... it's localized, provides dynamic error message depending on what kind of error it is. it will auto focus on the field that is wrong. You don't need any javascript - so less buggy. and hey you can still use the constraint validation https://codesource.io/validating-html-forms-using-javascript-and-constraint-validation-api/ along with js and do custom styling and css – Endless May 31 '21 at 16:33
  • Thank you @Endless - I appreciate the explanation and link and I'll take a look at this. Unfortunately, our codebase is a bit restrictive, so i had to go down this particular route. But this is all helpful and good to know. – Reena Verma May 31 '21 at 16:41

1 Answers1

1

This may not be what you're after, but I simplified things a bit in this function. There's no need to have your errors already sitting there waiting to be turned on/off as separate elements. You can just have a single error element and populate it with the error message.

function validateFirstName(e) {
  e.preventDefault();
  nameError = document.querySelector('#n-form-first-name-error');
  nameError.style.display = "none";
  let error = '';
  if (firstNameField.value.trim() == "") {
    error = "Please enter a first name";

  } else if (!checkFirstNameValidity(firstNameField.value.trim())) {
    error = "Please enter a valid first name";
  }
  if (error) {
    nameError.style.display = "block";
    nameError.innerHTML = error
  }

}

function checkFirstNameValidity(value) {
  return /^[^0-9+;:""`|!?<>().,\/\\@#$£%^&*]{1,30}$/.test(value);
};

const firstNameField = document.getElementById("n-form-first-name");
const nameError1 = document.getElementById("n-form-first-name-error-1");
const nameError2 = document.getElementById("n-form-first-name-error-2");

let isFirstNameFieldValid = "";
let isSecondNameFieldValid = "";

function validateFirstName(e) {
  e.preventDefault();
  nameError = document.querySelector('#n-form-first-name-error');
  nameError.style.display = "none";
  let error = '';
  if (firstNameField.value.trim() == "") {
    error = "Please enter a first name";

  } else if (!checkFirstNameValidity(firstNameField.value.trim())) {
    error = "Please enter a valid first name";
  }
  if (error) {
    nameError.style.display = "block";
    nameError.innerHTML = error
  }
   

   
};

function myFunction() {
  if (isFirstNameFieldValid === true) {
    console.log("isFirstNameFieldValid", isFirstNameFieldValid);
    nameError1.classList.remove("visible");
    firstNameField.classList.remove("invalid");
  } else {
    console.log("isFirstNameFieldValid", isFirstNameFieldValid);
  }

  if (isSecondNameFieldValid === true) {
    console.log("isSecondNameFieldValid", isSecondNameFieldValid);
    nameError2.classList.remove("visible");
    firstNameField.classList.remove("invalid");
  } else {
    console.log("isSecondNameFieldValid", isSecondNameFieldValid);
  }
};

firstNameField.addEventListener("input", validateFirstName);
/* First name */

#n-form-first-name-error-1,
#n-form-first-name-error-2 {
  display: none;
  font-size: 0.8em;
}

#n-form-first-name-error-1.visible {
  display: block;
}

#n-form-first-name-error-2.visible {
  display: block;
}

input[type=text].invalid {
  border-color: red;
}

input[type=text].valid {
  border-color: #f60;
}
<form>
  <div class="n-form-booker-contact-details">
    <!-- Contact Fields -->
    <div class="n-form-details">
      <!-- First Name -->
      <input type="text" id="n-form-first-name" name="n-form-first-name" placeholder="First name" onfocusout="myFunction()" required>
      <label for="n-form-first-name">First name</label>
      <div class="error" id="n-form-first-name-error" aria-live="polite">Please enter a first name</div>

    </div>
</form>
Kinglish
  • 23,358
  • 3
  • 22
  • 43
  • OMG this is perfect and just what I was looking for, thank you so much!!!! So you're displaying the error message styling, based on which error message is triggered? Thank you so much!! I knew there was a cleaner way to do this!! :) I wondered why you used .trim()? – Reena Verma May 31 '21 at 16:30
  • `.trim()` removes white space from the beginning and end of a string, so if I were to type in a bunch of spaces, I would still get the error, even though technically there were characters in there – Kinglish May 31 '21 at 16:31