0

I'm setting up a form that submits to a MySQL database via PHP and there are server-side validations that take place for security reasons. I would like the frontend validation messages to be handled with JavasScript because there are many similar forms on the site, and would like these linked to the input event listener.

In the following code the submit button has a preventDefault() method on it until the title is more than 10 characters long. I've read that the best way to add and remove preventDefault is via a click handler function, which I'm using.

By default the button has a .prevent-default class on it and this is removed when the input passes the validation.

The Issue I'm Experiencing

The preventDefault and the error message work if the form is submitted when less than 10 characters are typed, and of course if more than 10 characters are typed the form will just submit as expected.

However, when more than 10 characters are initially typed, and the user then deletes some characters to bring the count back below 10, the form still submits on the front end? I would like it to fail again, with the same error message showing after the submit button is clicked.

I think the solution is to toggle the checkValidations() function. I can't seem to be able to do this though.

NOTE: Some of the elements use the forEach loop because on the full site there will be multiple instances of the form.

CodePen Link: https://codepen.io/thechewy/pen/GROEmoN

var dmForm = document.querySelector("form"),
    
// class name on the submit button
preventSubmit = document.querySelectorAll(".prevent-submit"), 
dmTitle = document.querySelector("#dm-title"),
    
// empty element for error message
dmTitleError = document.querySelector(".js-dm-title-error")

// function that prevents default click action on button and adds warning message
var clickHandler = function(evt) {
    evt.preventDefault()
    if(dmTitle.value.length < 10) {
        dmTitleError.classList.add('warning')
        dmTitleError.textContent = "Title must be more than 10 characters"
    }
}

// checks for 'prevent-submit' class and if present invokes the clickHander function above
if (preventSubmit) {
  preventSubmit.forEach(item => {
    item.addEventListener('click', clickHandler, false)
})
  
  // removes warning when the user types more than 10 characters
  if (dmForm) {
    dmTitle.addEventListener('input', () => {
      if( dmTitle.value.length > 10) {
        dmTitleError.classList.remove('warning')
        dmTitleError.textContent = ""
        
        // call the function that removes the preventDefault method
        checkValidations()
      }
    })
  }

function checkValidations(){
  if (dmTitle.value.length > 10) {
    preventSubmit.forEach(item => {
      item.removeEventListener('click', clickHandler, false)
      item.classList.remove('prevent-submit')
    })
  }
}
  
} // end of 'if (preventSubmit)' statement
body {
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  padding: 0;
}

form {
  display: flex;
  align-items: center;
}

.input-wrapper {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
}

input,
button {
  padding: 0.5rem;
}

.js-error-message.warning {
    background: #cc1f1f;
    transition: background .5s;
    padding: 0.2rem 0.5rem;
    margin-top: 0.5rem;
    display: inline-block;
    position: absolute;
    bottom: -5rem;
}
<form method="post">
  <div class="input-wrapper">
    <input id="dm-title" name="dm-title">
    <p class="js-error-message js-dm-title-error"></p>
  </div>
  <button name="dm-submit" class="prevent-submit">SEND MESSAGE</button>
</form>

4 Answers 4

1
+150

Looks like you do need to remove validation everytime when all is OK, just execute preventDefault if an error is detected:

var dmForm = document.querySelector("form"),
    
// class name on the submit button
preventSubmit = document.querySelectorAll(".prevent-submit"), 
dmTitle = document.querySelector("#dm-title"),
    
// empty element for error message
dmTitleError = document.querySelector(".js-dm-title-error")

// function that prevents default click action on button and adds warning message
var clickHandler = function(evt) {
    
    if(dmTitle.value.length < 10) {
        dmTitleError.classList.add('warning')
        dmTitleError.textContent = "Title must be more than 10 characters"
evt.preventDefault(); // <-- prevent from sending and show warning
    }
}

// checks for 'prevent-submit' class and if present invokes the clickHander function above
if (preventSubmit) {
  preventSubmit.forEach(item => {
    item.addEventListener('click', clickHandler, false)
})
  
  // removes warning when the user types more than 10 characters
  if (dmForm) {
    dmTitle.addEventListener('input', () => {
      if( dmTitle.value.length > 10) {
        dmTitleError.classList.remove('warning')
        dmTitleError.textContent = ""
      }
        
        
    })
  }

  
  
} // end of 'if (preventSubmit)' statement
body {
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  padding: 0;
}

form {
  display: flex;
  align-items: center;
}

.input-wrapper {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
}

input,
button {
  padding: 0.5rem;
}

.js-error-message.warning {
    background: #cc1f1f;
    transition: background .5s;
    padding: 0.2rem 0.5rem;
    margin-top: 0.5rem;
    display: inline-block;
    position: absolute;
    bottom: -5rem;
}
<form method="post">
  <div class="input-wrapper">
    <input id="dm-title" name="dm-title">
    <p class="js-error-message js-dm-title-error"></p>
  </div>
  <button name="dm-submit" class="prevent-submit">SEND MESSAGE</button>
</form>

Sign up to request clarification or add additional context in comments.

Comments

1

This is easier to implement if you use the inbuilt DOM Constraint Validation API :

let form = document.querySelector("form");
let error = document.querySelector(".js-dm-title-error")
let title = document.getElementById('dm-title');

title.setAttribute("minLength", '10');

title.addEventListener('input', function(e) {
  if (!title.validity.valid) {
    // if you want to nag on every character entered
    //showError("Title must be more than 10 characters");
  } else {
    showError('');
  }
});

form.addEventListener('submit', function(event) {
  // check each field
  if (!title.validity.valid) {
    showError("Title must be more than 10 characters");
    event.preventDefault();
    return false;
  }

  // mimicking form submit
  output.innerHTML += `Sending ${title.value}...<br>`;
  event.preventDefault();
  return false;
});

function showError(msg) {
  if (msg) {
    error.classList.add('warning')
    error.textContent = msg;
  } else {
    error.classList.remove('warning');
  }
}
body {
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
  padding: 0;
}

form {
  display: flex;
  align-items: center;
}

.input-wrapper {
  position: relative;
}

input {
  display: block;
  margin-right: 0.5rem;
  border-radius: 0.3rem;
}

input:invalid {
  background-color: rgb(255, 220, 220);
}

input:invalid:required {
  border: 1px dashed red;
}

input:valid {
  background-color: rgb(211, 255, 211);
}

.js-error-message {
  display: none;
  position: absolute;
  top: 100%;
}

.js-error-message.warning {
  display: inline-block;
  padding: .2rem;
  width: 169px;
  font-size: 80%;
  color: white;
  background-color: #900;
  border-radius: 0 0 5px 5px;
  box-sizing: border-box;
}
<form method="post" novalidate>
  <div class="input-wrapper">
    <input id="dm-title" name="dm-title" required>
    <div class="js-error-message js-dm-title-error"></div>
  </div>
  <button name="dm-submit" class="prevent-submit">SEND MESSAGE</button>
</form><br>
<div id=output></div>

Comments

1

Checking form.onsubmit event would be more suitable.

https://codepen.io/_yigitt/pen/JjOpmPW

form1.onsubmit = function () {
    if (inputFirstName.value.length < 10) {
        p_error.classList.add("warning");
        p_error.textContent = "Title must be more than 10 characters";
        return false;
    }
};

inputFirstName.oninput = function () {
    if (this.value.length > 10) {
        p_error.classList.remove("warning");
        p_error.textContent = "";
    }
};

Comments

0

The validation needed is already built in -- no JavaScript is required. It's better UX to flash error messages when there's a real error. It's irritating to see messages popping up about requirements not being met when you just started typing. It's best just to show error messages at the submit event.

The input found in the example below has two attributes:

  • minlength="11" At submit if the input has 10 or less characters, the form will cease submitting and an error message pops up.

  • required At submit if the input is empty, the form will cease submitting and an error message pops up.

Also, there's no weird behavior (ex. enter 12 chars, remove 5 and submit successfully) in this simple validation. Also in the example, data is sent to a live test server and the iframe is there to show server response.

<!DOCTYPE html>
<html lang="en">

<head>
  <title></title>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  <style>
    *,
    *::before,
    *::after {
      box-sizing: border-box;
    }
    
     :root {
      font: 1ch/1.25 'Segoe UI';
    }
    
    html,
    body {
      width: 100%;
      min-height: 100%;
      margin: 0;
      padding: 0;
    }
    
    body {
      display: flex;
      flex-flow: row nowrap;
      justify-content: center;
      align-items: center;
      font-size: 2.5rem;
    }
    
    main {
      width: 100%;
      height: 100%;
      margin: 0 auto;
    }
    
    input,
    output,
    button {
      display: inline-block;
      font-size: 100%;
    }
    
    input,
    output {
      font-family: Consolas;
      line-height: 1.15;
    }
    
    button {
      width: max-content;
      padding: 2px 4px;
      border-radius: 4px;
    }
  </style>
</head>

<body>
  <main>
    <form action='https://httpbin.org/post' method="post" target='response'>
      <fieldset>
        <legend>Direct Message</legend>
        <input id="message" name="message" minlength='11' required>
        <button name='btn'>Send Message</button>
      </fieldset>
      <fieldset>
        <legend>Server Response</legend>
        <iframe name='response'></iframe>
      </fieldset>
    </form>
  </main>
  <script></script>
</body>

</html>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.