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 >
<input id="dm-title" name="dm-title">
<p ></p>
</div>
<button name="dm-submit" >SEND MESSAGE</button>
</form>
CodePudding user response:
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 >
<input id="dm-title" name="dm-title">
<p ></p>
</div>
<button name="dm-submit" >SEND MESSAGE</button>
</form>
CodePudding user response:
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 >
<input id="dm-title" name="dm-title" required>
<div ></div>
</div>
<button name="dm-submit" >SEND MESSAGE</button>
</form><br>
<div id=output></div>