Check all input's validity first, then submit Vanilla JS - javascript

I'm working on a form page that has multiple input fields. There is some error text to show if the inputs are not valid.
After the user submits all the input fields correctly I want to show a modal. The form validation is working almost fine except for the CVC input. It's only checking when the CVC field is empty.
What can I do to fix this?
const form = document.querySelector('form');
const inputs = document.querySelectorAll('input');
const modal = document.querySelector('.modal');
const modalClose = document.querySelector('.close');
form.addEventListener('submit',(e)=>{
e.preventDefault();
inputs.forEach(input=>{
if(input.classList.contains('name-input')){
containsNameInput(input)
}else if(input.classList.contains('date')){
containsDateInput(input)
}else{
containsOtherInput(input)
}
if(input.parentElement.classList.contains('error-empty')
|| input.parentElement.classList.contains('error-invalid')
||input.parentElement.parentElement.classList.contains('error-invalid')
|| input.parentElement.parentElement.classList.contains('error-empty')){
modal.style.display = 'none';
}else{
modal.style.display = "block";
}
})
})
const containsNameInput = function(input){
if(input.value === ''){
input.parentElement.classList.add('error-empty');
input.parentElement.classList.remove('error-invalid');
}else if(input.value !== '' && input.value.match(/^[0-9]+$/) !== null){
input.parentElement.classList.remove('error-empty');
input.parentElement.classList.add('error-invalid');
}
else{
input.parentElement.classList.remove('error-empty');
input.parentElement.classList.remove('error-invalid');
}
}
const containsDateInput = function(input){
if(input.value === ''){
input.parentElement.parentElement.classList.add('error-empty');
input.parentElement.parentElement.classList.remove('error-invalid');
}else if(input.value !== '' && input.value.match(/^[0-9]+$/) === null){ // wil return null if value has anything accept number
input.parentElement.parentElement.classList.remove('error-empty');
input.parentElement.parentElement.classList.add('error-invalid');
}else{
input.parentElement.parentElement.classList.remove('error-empty');
input.parentElement.parentElement.classList.remove('error-invalid');
}
}
const containsOtherInput = function(input){
if(input.value === ''){
input.parentElement.classList.add('error-empty');
input.parentElement.classList.remove('error-invalid');
}else if(input.value !== '' && input.value.match(/^[0-9]+$/) === null){
input.parentElement.classList.remove('error-empty');
input.parentElement.classList.add('error-invalid');
}else{
input.parentElement.classList.remove('error-empty');
input.parentElement.classList.remove('error-invalid');
}
}
modalClose.addEventListener('click',()=>{
modal.style.display = "none";
})
.input-field .error{
color: red;
font-size: .7rem;
display: none;
}
.input-field.error-empty .empty{
display: block;
}
.input-field.error-invalid .invalid{
display: block;
}
.modal{
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: none;
background:white;
}
<form>
<div class="input-field">
<label for="name">Cardholder Name</label>
<input type="text" placeholder="e.g. Jane Appleseed" id="name" name="name" maxlength="25" class="name-input">
<p class="error empty">Can't be blank</p>
<p class="error invalid">Wrong format, letters only</p>
</div>
<div class="input-field">
<label for="number">Card Number</label>
<input type="text" placeholder="e.g. 1234 5678 9123 0000" id="number" name="number" minlength="16" maxlength="16" class="number-input">
<p class="error empty">Can't be blank</p>
<p class="error invalid">Wrong format, numbers only</p>
</div>
<div class="flex-row">
<div class="input-field date-container">
<label id='date'>Exp. Date (MM/YY)</label>
<div class="date-input">
<input type='text' placeholder="MM" id='month' name="month" aria-labelledby='date' class="date month-input" maxlength="2"/>
<input type='text' placeholder="YY" id='year' name="year" aria-labelledby='date' class="date year-input" maxlength="2"/>
</div>
<p class="error empty">Can't be blank</p>
<p class="error invalid">Wrong format, numbers only</p>
</div>
<div class="input-field">
<label for="cvc">CVC</label>
<input type="text" placeholder="e.g. 123" id="cvc" name="cvc" maxlength="4" class="cvc-input">
<p class="error empty">Can't be blank</p>
<p class="error invalid">Wrong format, numbers only</p>
</div>
</div>
<button type="submit" class="btn">Confirm</button>
</form>
<section class="modal">
<img src="./images/icon-complete.svg" alt="">
<h2>Thank you!</h2>
<p>We've added your card details</p>
<button type="button" class="btn close">Continue</button>
</section>

Classic bug: the result "variable" (here: visibility) gets set after every check, so it will contain the result of the last check and nothing else. Instead you should assume success at the beginning, and only set on failure of a check (and never set to success again). Then if any check fails, the entire thing will fail too.
const form = document.querySelector('form');
const inputs = document.querySelectorAll('input');
const modal = document.querySelector('.modal');
const modalClose = document.querySelector('.close');
form.addEventListener('submit', (e) => {
e.preventDefault();
modal.style.display = "block"; // assume things go well
inputs.forEach(input => {
if (input.classList.contains('name-input')) {
containsNameInput(input)
} else if (input.classList.contains('date')) {
containsDateInput(input)
} else {
containsOtherInput(input)
}
if (input.parentElement.classList.contains('error-empty') ||
input.parentElement.classList.contains('error-invalid') ||
input.parentElement.parentElement.classList.contains('error-invalid') ||
input.parentElement.parentElement.classList.contains('error-empty')) {
modal.style.display = 'none'; // act when they do not
// }else{
// modal.style.display = "block";
}
})
})
const containsNameInput = function(input) {
if (input.value === '') {
input.parentElement.classList.add('error-empty');
input.parentElement.classList.remove('error-invalid');
} else if (input.value !== '' && input.value.match(/^[0-9]+$/) !== null) {
input.parentElement.classList.remove('error-empty');
input.parentElement.classList.add('error-invalid');
} else {
input.parentElement.classList.remove('error-empty');
input.parentElement.classList.remove('error-invalid');
}
}
const containsDateInput = function(input) {
if (input.value === '') {
input.parentElement.parentElement.classList.add('error-empty');
input.parentElement.parentElement.classList.remove('error-invalid');
} else if (input.value !== '' && input.value.match(/^[0-9]+$/) === null) { // wil return null if value has anything accept number
input.parentElement.parentElement.classList.remove('error-empty');
input.parentElement.parentElement.classList.add('error-invalid');
} else {
input.parentElement.parentElement.classList.remove('error-empty');
input.parentElement.parentElement.classList.remove('error-invalid');
}
}
const containsOtherInput = function(input) {
if (input.value === '') {
input.parentElement.classList.add('error-empty');
input.parentElement.classList.remove('error-invalid');
} else if (input.value !== '' && input.value.match(/^[0-9]+$/) === null) {
input.parentElement.classList.remove('error-empty');
input.parentElement.classList.add('error-invalid');
} else {
input.parentElement.classList.remove('error-empty');
input.parentElement.classList.remove('error-invalid');
}
}
modalClose.addEventListener('click', () => {
modal.style.display = "none";
})
.input-field .error {
color: red;
font-size: .7rem;
display: none;
}
.input-field.error-empty .empty {
display: block;
}
.input-field.error-invalid .invalid {
display: block;
}
.modal {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: none;
background: white;
}
<form>
<div class="input-field">
<label for="name">Cardholder Name</label>
<input type="text" placeholder="e.g. Jane Appleseed" id="name" name="name" maxlength="25" class="name-input">
<p class="error empty">Can't be blank</p>
<p class="error invalid">Wrong format, letters only</p>
</div>
<div class="input-field">
<label for="number">Card Number</label>
<input type="text" placeholder="e.g. 1234 5678 9123 0000" id="number" name="number" minlength="16" maxlength="16" class="number-input">
<p class="error empty">Can't be blank</p>
<p class="error invalid">Wrong format, numbers only</p>
</div>
<div class="flex-row">
<div class="input-field date-container">
<label id='date'>Exp. Date (MM/YY)</label>
<div class="date-input">
<input type='text' placeholder="MM" id='month' name="month" aria-labelledby='date' class="date month-input" maxlength="2" />
<input type='text' placeholder="YY" id='year' name="year" aria-labelledby='date' class="date year-input" maxlength="2" />
</div>
<p class="error empty">Can't be blank</p>
<p class="error invalid">Wrong format, numbers only</p>
</div>
<div class="input-field">
<label for="cvc">CVC</label>
<input type="text" placeholder="e.g. 123" id="cvc" name="cvc" minlength="3" maxlength="4" class="cvc-input">
<p class="error empty">Can't be blank</p>
<p class="error invalid">Wrong format, numbers only</p>
</div>
</div>
<button type="submit" class="btn">Confirm</button>
</form>
<section class="modal">
<img src="./images/icon-complete.svg" alt="">
<h2>Thank you!</h2>
<p>We've added your card details</p>
<button type="button" class="btn close">Continue</button>
</section>
According to internet sources, CVC is either 3 or 4 digits, so added a minlength="3".

html does all the blank validation by itself. i am adding required attribute on every input tag
const form = document.querySelector('form');
const inputs = document.querySelectorAll('input');
const modal = document.querySelector('.modal');
const modalClose = document.querySelector('.close');
form.addEventListener('submit', (e) => {
e.preventDefault();
inputs.forEach(input => {
if (input.classList.contains('name-input')) {
containsNameInput(input)
} else if (input.classList.contains('date')) {
containsDateInput(input)
} else {
containsOtherInput(input)
}
})
})
inputs.forEach(input => {
if (input.parentElement.classList.contains('error-empty')
|| input.parentElement.classList.contains('error-invalid')
|| input.parentElement.parentElement.classList.contains('error-invalid')
|| input.parentElement.parentElement.classList.contains('error-empty')) {
modal.style.display = "block";
} else {
modal.style.display = "none";
}
})
const containsNameInput = function (input) {
if (input.value === '') {
input.parentElement.classList.add('error-empty');
input.parentElement.classList.remove('error-invalid');
} else if (input.value !== '' && input.value.match(/^[0-9]+$/) !== null) {
input.parentElement.classList.remove('error-empty');
input.parentElement.classList.add('error-invalid');
}
else {
input.parentElement.classList.remove('error-empty');
input.parentElement.classList.remove('error-invalid');
}
}
const containsDateInput = function (input) {
if (input.value === '') {
input.parentElement.parentElement.classList.add('error-empty');
input.parentElement.parentElement.classList.remove('error-invalid');
} else if (input.value !== '' && input.value.match(/^[0-9]+$/) === null) { // wil return null if value has anything accept number
input.parentElement.parentElement.classList.remove('error-empty');
input.parentElement.parentElement.classList.add('error-invalid');
} else {
input.parentElement.parentElement.classList.remove('error-empty');
input.parentElement.parentElement.classList.remove('error-invalid');
}
}
const containsOtherInput = function (input) {
if (input.value === '') {
input.parentElement.classList.add('error-empty');
input.parentElement.classList.remove('error-invalid');
} else if (input.value !== '' && input.value.match(/^[0-9]+$/) === null) {
input.parentElement.classList.remove('error-empty');
input.parentElement.classList.add('error-invalid');
} else {
input.parentElement.classList.remove('error-empty');
input.parentElement.classList.remove('error-invalid');
}
}
modalClose.addEventListener('click', () => {
modal.style.display = "none";
})
.input-field .error{
color: red;
font-size: .7rem;
display: none;
}
.input-field.error-empty .empty{
display: block;
}
.input-field.error-invalid .invalid{
display: block;
}
.modal{
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: none;
background:white;
}
<form>
<div class="input-field">
<label for="name">Cardholder Name</label>
<input type="text" placeholder="e.g. Jane Appleseed" id="name" name="name" maxlength="25" class="name-input" >
<p class="error empty">Can't be blank</p>
<p class="error invalid">Wrong format, letters only</p>
</div>
<div class="input-field">
<label for="number">Card Number</label>
<input type="text" placeholder="e.g. 1234 5678 9123 0000" id="number" name="number" minlength="16" maxlength="16" class="number-input" >
<p class="error empty">Can't be blank</p>
<p class="error invalid">Wrong format, numbers only</p>
</div>
<div class="flex-row">
<div class="input-field date-container">
<label id='date'>Exp. Date (MM/YY)</label>
<div class="date-input">
<input type='text' placeholder="MM" id='month' name="month" aria-labelledby='date' class="date month-input" maxlength="2" />
<input type='text' placeholder="YY" id='year' name="year" aria-labelledby='date' class="date year-input" maxlength="2"/>
</div>
<p class="error empty">Can't be blank</p>
<p class="error invalid">Wrong format, numbers only</p>
</div>
<div class="input-field">
<label for="cvc">CVC</label>
<input type="text" placeholder="e.g. 123" id="cvc" name="cvc" maxlength="4" class="cvc-input" >
<p class="error empty">Can't be blank</p>
<p class="error invalid">Wrong format, numbers only</p>
</div>
</div>
<button type="submit" class="btn">Confirm</button>
</form>
<section class="modal">
<img src="./images/icon-complete.svg" alt="">
<h2>Thank you!</h2>
<p>We've added your card details</p>
<button type="button" class="btn close">Continue</button>
</section>

Related

preventDefault not preventing submit form

I have problems with my form submittiting even if the fields are not valid.
I've tried a lot of different code, but I'm currently with this.
const form = document.getElementById('kontaktskjema');
const email = document.getElementById('mail');
const emailError = document.querySelector('#mail + span.errorkontakt');
const navn = document.getElementById('navn');
const navnError = document.querySelector('#navn + span.errorkontakt');
const telefon = document.getElementById('telefon');
const telefonError = document.querySelector('#telefon + span.errorkontakt')
const message = document.getElementById('message');
const messageError = document.querySelector('#message + span.errorkontakt')
const navnboks = document.querySelector('.navnboks')
const teleboks = document.querySelector('.teleboks')
const mailboks = document.querySelector('.mailboks')
const messageboks = document.querySelector('.messageboks')
const vernboks = document.querySelector('.vernboks')
const personvern = document.getElementById('checkbox');
const personvernError = document.querySelector('#checkbox + span.errorkontakt')
const submitbtn = document.getElementById('submitbtn');
// THIS DIV WILL CONTAIN ERROR MESSAGES
const errOutput = document.querySelector('.errorsOutput')
email.addEventListener('input', function (event) {
if (email.validity.valid) {
mailboks.setAttribute("class", "data-validation-error-ok" )
emailError.innerHTML = '';
emailError.className = 'errorkontakt';
} else {
showError();
}
});
navn.addEventListener('input', function (event) {
if (navn.validity.valid) {
navnError.innerHTML = '';
navnError.className = 'errorkontakt';
navnboks.setAttribute("class", "data-validation-error-ok" )
} else {
showError();
}
})
telefon.addEventListener('input', function (event) {
if (telefon.validity.valid) {
telefonError.innerHTML = '';
telefonError.className = 'errorkontakt';
teleboks.setAttribute("class", "data-validation-error-ok" )
} else {
showError();
}
})
message.addEventListener('input', function (event) {
if (message.validity.valid) {
messageboks.setAttribute("class", "data-validation-error-ok" )
messageError.innerHTML = '';
messageError.className = 'errorkontakt';
} else {
showError();
}
})
personvern.addEventListener('change', function (event) {
if (personvern.checked == true) {
vernboks.setAttribute("class", "data-validation-error-ok" )
} else {
showError();
}
})
function makeRed() {
if (!navn.validity.valid) {
navnboks.setAttribute("class", "data-validation-error-true")
}
if (!email.validity.valid) {
mailboks.setAttribute("class", "data-validation-error-true")
}
if (!telefon.validity.valid) {
teleboks.setAttribute("class", "data-validation-error-true")
}
if (!message.validity.valid) {
messageboks.setAttribute("class", "data-validation-error-true")
}
if (!personvern.checked == true) {
vernboks.setAttribute("class", "data-validation-error-true")
}
};
function divFill() {
if (navnError.textContent != '') {
errOutput.innerHTML += '<li>Navn</li>'
}
if (emailError.textContent != '') {
errOutput.innerHTML += '<li>E-mail</li>'
}
if (telefonError.textContent != '') {
errOutput.innerHTML += '<li>Telefonnummer</li>'
}
if (messageError.textContent != '') {
errOutput.innerHTML += '<li>Beskjed</li>'
}
}
function showError() {
errOutput.innerHTML = ''
if(navn.validity.valueMissing) {
navnError.textContent = '* Du må fylle inn navnet ditt';
navnError.setAttribute("class", "data-validation-error-true" )
} else if(navn.validity.tooShort) {
navnError.textContent = '* Du må fylle inn hele navnet ditt'
}
if(email.validity.valueMissing) {
emailError.setAttribute("class", "data-validation-error-true" )
emailError.textContent = '* Vennligst fyll inn e-posten din';
} else if(email.validity.typeMismatch) {
emailError.textContent = '* Dette er ikke en gyldig e-postadresse.';
} else if(email.validity.tooShort) {
emailError.textContent = `* Email should be at least ${ email.minLength } characters; you entered ${ email.value.length }.`;
}
if(telefon.validity.valueMissing) {
telefonError.textContent = '* Du må fylle inn telefonnummeret ditt'
telefonError.setAttribute("class", "data-validation-error-true" )
} else if(telefon.validity.tooShort) {
telefonError.textContent = '* Du mangler ett eller flere tall. Vennligst dobbeltsjekk.'
}
if(message.validity.valueMissing) {
messageError.setAttribute("class", "data-validation-error-true" )
messageError.textContent = '* Beskjeden mangler, vennligst fyll inn'
} else if(message.validity.tooShort) {
messageError.textContent = `* Beskjed må være minst ${ message.minLength } tegn.`;
}
}
emailError.className = 'errorkontakt kontaktactive';
navnError.className = 'errorkontakt kontaktactive';
telefonError.className = 'errorkontakt kontaktactive';
messageError.className ='errorkontakt kontaktactive';
console.log(form)
form.addEventListener('submit', function(event) {
if (!navn.validity.valid || !email.validity.valid || !telefon.validity.valid || !message.validity.valid) {
makeRed();
divFill();
event.preventDefault();
console.log('Runs')
}})
<div id="contact-form-wrapper" class="align-right-50 lazyload">
<div id="contact-form-padding">
<h2>Send oss en melding</h2>
<p><span class="required">*</span> obligatorisk felt som du må fylle ut</p><br>
<div class="errorsOutput">
</div>
<div class="skjema">
<form id="kontaktskjema" action="nyhandler.kontakt.php" method="post" novalidate>
<input type="hidden" id="sendtfra" name="Sidetittel" value="{title}" />
<input type="hidden" id="sendtfraURL" name="Side URL" value="{url}" />
<div class="navnboks">
<p>
<label for="navn">
<span>* Navn:</span>
<input type="text" id="navn" name="navn" required minlength="3" class="input-text w100">
<span class="errorkontakt" aria-live="polite"></span>
</label>
</p>
</div>
<div class="mailboks">
<p>
<label for="mail">
<span>* E-post:</span>
<input type="email" id="mail" name="mail" required minlength="6" class="input-text w100">
<span class="errorkontakt" aria-live="polite"></span>
</label>
</p>
</div>
<div class="teleboks">
<p>
<label for="telefon">
<span>* Telefonnummer:</span>
<input type="tel" id="telefon" name="telefon" required minlength="8" class="input-text w100">
<span class="errorkontakt" aria-live="polite"></span>
</label>
</p>
</div>
<div class="messageboks">
<p>
<label for="message">
<span>* Melding:</span>
<input type="text" id="message" name="message" required minlength="10" class="input-text w100">
<span class="errorkontakt" aria-live="polite"></span>
</label>
</p>
</div>
<div class="vernboks">
<input type="hidden" id="recapta" name="g-recaptcha-response" />
<p>
<label for="personvern">
<div class="personvern">
<span>* Personvern:</span>
<br>
<input type="checkbox" id="checkbox" name="checkbox" required>
<span>Jeg har lest og godkjent Personvernserklæringen (åpnes i nytt vindu)</span>
<span class="errorkontakt" aria-live="polite"></span>
</div>
</label>
</p>
</div>
<button type="submit" value="Send" class="button-send">Send</button>
</form>
</div>
</div>
</div>
<div class="clear"></div>
</div>
I know it's weirdly specific, and i'll probably clean it up after i get it to work. Right now the validation completes, and runs the functions makeRed() and divFill(), both functions are there to help with accessability issues when not valid, but the form still submits and goes to the handler php.
Thanks.
getElementsByTagName
will return the form tag's value in [0]th location.
So you might need to change your first line of your javascript code as :
const form = document.getElementsByTagName('form')[0];
It will work .

Javascript How to add an html element using javascript

can anyone help me to add this icon <i class="fas fa-check-circle"></i> if the background color changes to green using the following code:
document.querySelectorAll('input').forEach((inp) => {
inp.addEventListener('focusout', () => {
let value = inp.value.split(' ').join('')
if (value == '') {
inp.style.backgroundColor = "red";
} else {
inp.style.backgroundColor = "green";
let icon = document.createElement('i')
icon.classList.add('fas', 'fa-check-circle')
inp.appendChild(icon)
}
})
})
HTML Code
<section class="control-group">
<label class="control-label" for="company">Company</label>
<div class="controls">
<input
autofocus=""
class="input-xlarge"
id="company"
name="company"
placeholder="Company name"
type="text"
value=""
/>
</div>
</section>
<section class="control-group">
<label class="control-label" for="fname">Name</label>
<div class="controls two-col">
<input
class="input-medium"
id="fname"
name="fname"
placeholder="First name"
type="text"
value=""
/>
</div>
the excepted result is that the icon should be nest to every text field that has been filled.
You are trying tp append a child to an input. An input does not have children. You need to add it after the input. Also with your code, it would add a bunch of elements every time it loses focus.
document.querySelectorAll('input').forEach((inp) => {
let icon = document.createElement('i')
icon.classList.add('fas', 'fa-check-circle', 'hidden')
inp.after(icon);
inp.addEventListener('focusout', () => {
let value = inp.value.split(' ').join('')
if (value == '') {
inp.style.backgroundColor = "red";
icon.classList.add('hidden');
} else {
icon.style.display = 'inilne-block';
inp.style.backgroundColor = "green";
icon.classList.remove('hidden');
}
})
})
input {
padding-right: 20px;
}
input + i {
position: absolute;
margin-left: -20px;
}
i.hidden {
display: none;
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css">
<input type="text"><input type="text"><input type="text">
You cannot add children to an input element. However, you can add the icon next to the input by means of insertAdjacentHTML().
document.querySelectorAll('input').forEach((inp) => {
inp.addEventListener('focusout', () => {
let value = inp.value.split(' ').join('')
if (value == '') {
inp.style.backgroundColor = "red";
} else {
inp.style.backgroundColor = "green";
inp.insertAdjacentHTML('afterend', '<i class="fas fa-check-circle">Your icon here</i>');
}
})
})
<input type="text">
If you want the icon "inside" the input, then you need to use CSS to set it as a background image, which is not related to "adding a HTML element using JavaScript".
I would suggest that rather than adding new elements in response to user input, you build all the elements into your html, and then hide/show/style them appropriately with a css class or two:
document.querySelectorAll('input').forEach((inp) => {
inp.addEventListener('focusout', () => {
const parent = inp.parentNode;
let value = inp.value.split(' ').join('');
if (value == '') {
parent.classList.remove("valid");
parent.classList.add("invalid");
} else {
parent.classList.remove("invalid");
parent.classList.add("valid");
}
});
});
.controls i {
display: none;
}
.controls.valid input {
background-color: green;
}
.controls.valid i {
display: inline;
}
.controls.invalid input {
background-color: red;
}
<section class="control-group">
<label class="control-label" for="company">Company</label>
<div class="controls">
<input
autofocus=""
class="input-xlarge"
id="company"
name="company"
placeholder="Company name"
type="text"
value=""
/>
<i class="fas fa-check-circle">test</i>
</div>
</section>
<section class="control-group">
<label class="control-label" for="fname">Name</label>
<div class="controls two-col">
<input
class="input-medium"
id="fname"
name="fname"
placeholder="First name"
type="text"
value=""
/>
<i class="fas fa-check-circle">test</i>
</div>
</section>
elem = document.createElement("<div id='myID'> my Text </div>");

eventListener works on click 1. But fails on click 2

So i am making a signup form with action="signup.inc.php" But im handling the validation in javascript.
If the fields are empty or the password don't match the input gets a red border and the placeholder is replaced.
This works perfectly on the first click. But as soon as i click again he just shoots to signup.inc.php.
I need those validations to be done before we go to the signup.inc.php file.
let signupForm = document.getElementById('signupForm');
let firstname = document.getElementById('firstname');
let lastname = document.getElementById('lastname');
let email = document.getElementById('email');
let username = document.getElementById('username');
let password = document.getElementById('password');
let passwordRepeat = document.getElementById('passwordRepeat');
let result = false;
function showError(input, message) {
let formControl = input.parentElement;
formControl.className = 'formControl error';
let error = input;
error.placeholder = message;
}
function showSucces(input) {
let formControl = input.parentElement;
formControl.className = 'formControl succes';
}
function requiredFields(inputArr) {
inputArr.forEach(function (input){
if (input.value.trim() === ''){
showError(input, 'this field is required');
} else {
showSucces(input);
result = true;
}
});
}
function matchPasswords(input1, input2) {
if (input1.value !== input2.value) {
showError(input2, "These passwords don't match");
} else {
result = true;
}
}
/* Eventlistener */
signupForm.addEventListener('submit', function(e){
if (result !== true) {
requiredFields ([firstname, lastname, email, username, password, passwordRepeat]);
matchPasswords (password, passwordRepeat);
e.preventDefault();
} else {
result = true;
}
});
.signupFormWrap {
margin-bottom: 15px;
}
.signupFormWrap,
.formControl {
width: 400px;
display: flex;
flex-direction: column;
}
.formControl label {
font-size: 1.2rem;
}
.formControl>input[type=text],
input[type=email],
input[type=password] {
padding-left: 10px;
font-size: 1rem;
line-height: 1.8;
}
.button {
margin-top: 15px;
margin-bottom: 15px;
}
.formControl.error>input {
border: 1px solid red;
}
.formControl.succes>input {
border: 1px solid green;
}
<form name="signupForm" id="signupForm" action="assets/php/signup.inc.php" method="POST">
<div class="signupFormWrap">
<div class="formControl">
<label for="firstname">Firstname</label>
<input type="text" name="firstname" id="firstname" placeholder="Fill in your firstname here..">
</div>
<div class="formControl">
<label for="lastname">lastname</label>
<input type="text" name="lastname" id="lastname" placeholder="Fill in your lastname here..">
</div>
<div class="formControl">
<label for="email">Email</label>
<input type="email" name="email" id="email" placeholder="Fill in your email here..">
</div>
<div class="formControl">
<label for="username">Username</label>
<input type="text" name="username" id="username" placeholder="Fill in your username here..">
</div>
<div class="formControl">
<label for="password">Password</label>
<input type="password" name="password" id="password" placeholder="fill in your password here..">
</div>
<div class="formControl">
<label for="passwordRepeat">Verify your password</label>
<input type="password" name="passwordRepeat" id="passwordRepeat" placeholder="Verify your password">
</div>
<button type="submit" name="submit" class="button">Sign up</button>
</div>
</form>
Your problem is that if any of the inputs are valid, result is set to true and so on the next submit the inputs are not checked and the form submits. You can work around that by always testing all the inputs, returning the error status from each input checking function and checking that they all return true:
let signupForm = document.getElementById('signupForm');
let firstname = document.getElementById('firstname');
let lastname = document.getElementById('lastname');
let email = document.getElementById('email');
let username = document.getElementById('username');
let password = document.getElementById('password');
let passwordRepeat = document.getElementById('passwordRepeat');
function showError(input, message) {
let formControl = input.parentElement;
formControl.className = 'formControl error';
let error = input;
error.placeholder = message;
}
function showSucces(input) {
let formControl = input.parentElement;
formControl.className = 'formControl succes';
}
function requiredFields(inputArr) {
result = true;
inputArr.forEach(function(input) {
if (input.value.trim() === '') {
showError(input, 'this field is required');
result = false;
} else {
showSucces(input);
}
});
return result;
}
function matchPasswords(input1, input2) {
result = true;
if (input1.value !== input2.value) {
showError(input2, "These passwords don't match");
result = false;
}
return result;
}
/* Eventlistener */
signupForm.addEventListener('submit', function(e) {
let result = true;
result = result && requiredFields([firstname, lastname, email, username, password, passwordRepeat]);
result = result && matchPasswords(password, passwordRepeat);
if (!result) {
e.preventDefault();
}
});
.signupFormWrap {
margin-bottom: 15px;
}
.signupFormWrap,
.formControl {
width: 400px;
display: flex;
flex-direction: column;
}
.formControl label {
font-size: 1.2rem;
}
.formControl>input[type=text],
input[type=email],
input[type=password] {
padding-left: 10px;
font-size: 1rem;
line-height: 1.8;
}
.button {
margin-top: 15px;
margin-bottom: 15px;
}
.formControl.error>input {
border: 1px solid red;
}
.formControl.succes>input {
border: 1px solid green;
}
<form name="signupForm" id="signupForm" action="assets/php/signup.inc.php" method="POST">
<div class="signupFormWrap">
<div class="formControl">
<label for="firstname">Firstname</label>
<input type="text" name="firstname" id="firstname" placeholder="Fill in your firstname here..">
</div>
<div class="formControl">
<label for="lastname">lastname</label>
<input type="text" name="lastname" id="lastname" placeholder="Fill in your lastname here..">
</div>
<div class="formControl">
<label for="email">Email</label>
<input type="email" name="email" id="email" placeholder="Fill in your email here..">
</div>
<div class="formControl">
<label for="username">Username</label>
<input type="text" name="username" id="username" placeholder="Fill in your username here..">
</div>
<div class="formControl">
<label for="password">Password</label>
<input type="password" name="password" id="password" placeholder="fill in your password here..">
</div>
<div class="formControl">
<label for="passwordRepeat">Verify your password</label>
<input type="password" name="passwordRepeat" id="passwordRepeat" placeholder="Verify your password">
</div>
<button type="submit" name="submit" class="button">Sign up</button>
</div>
</form>
change all validation functions like
function matchPasswords(input1, input2) {
if (input1.value !== input2.value) {
showError(input2, "These passwords don't match");
return false;
}
return true;
}
signupForm.addEventListener('submit', function(e){
if(!requiredFields ([firstname, lastname, email, username, password, passwordRepeat]) &&
!matchPasswords (password, passwordRepeat)){
e.preventDefault();
}
});

How show basic validation messages in the text field

I want to show the validation messages below the text fields that require it as well as the example that is in the image that I found
Example
I have the following text fields on my form, with their respective validation done in Javascript
//Function to validate ticket form
function validate_form() {
valid = true;
if (document.ticketForm.matricula.value == "") {
alert("Verify the data again, enter the license plate");
valid = false;
}
if (document.ticketForm.nombre.value == "") {
alert("Verify the data again, enter the name of the applicant");
valid = false;
}
return valid;
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<form name="ticketForm" method="post" onchange="validate_form();">
<div id="informacionTicket" class="user">
<div class="card shadow mb-4">
<div class="card-body">
<div class="mb-4">
<div class="form-group">
<label for="ticketIdAppliInput">License:</label>
<input maxlength="9" required id="ticketIdAppliInput" type="text" name="matricula" onkeypress="if (isNaN(String.fromCharCode(event.keyCode))) return false;" class="form-control form-control-user" />
</div>
<div class="form-group">
<label for="ticketNameAppliInput">Full name:</label>
<input maxlength="100" id="ticketNameAppliInput" type="text" name="nombre" class="form-control form-control-user" />
</div>
<div class="form-group">
<label for="ticketEmailAppliInput">Email:</label>
<input maxlength="100" id="ticketEmailAppliInput" type="email" name="email" class="form-control form-control-user" />
</div>
</div>
</div>
</div>
</div>
<button type="button" id="submit" class="btn btn-primary btn-user btn-block">Send</button>
</form>
What I don't want is to be shown those annoying alert at the top of the form
I want the message to be displayed as in the example image
UPDATE:
Try this possible solution but when entering a value the message is no longer deleted
UPDATE:
I tried the possible solution of #JarlikStepsto but it still doesn't work properly
function validate(field) {
const validateables = document.getElementsByClassName('validateable');
const input = field;
if (!input.value == "") {
input.classList.add('invalid');
} else {
input.classList.remove('invalid');
}
if (!input.value == "") {
input.classList.add('invalid');
} else {
input.classList.remove('invalid');
}
}
input {
display: block;
}
.validation-message {
display: none;
}
input.validateable.invalid + .validation-message {
display: block;
color: red;
}
<div class="form-group">
<label class="required-field" name="matricula" for="ticketIdAppliInput">Matrícula:</label>
<input onchange="validate(this)" maxlength="9" required="required" id="ticketIdAppliInput" type="text" name="matricula" onkeypress="if (isNaN(String.fromCharCode(event.keyCode))) return false;" class="form-control form-control-user validateable"/>
<div class="validation-message">
Verifique la información nuevamente, ingrese la matricula</div>
</div>
<div class="form-group">
<label class="required-field" name="nombre" for="ticketNameAppliInput">Nombre completo:</label>
<input onchange="validate(this)" maxlength="100" id="ticketNameAppliInput" type="text" name="nombre" class="form-control form-control-user validateable" />
<div class="validation-message">
Verifique la información nuevamente, ingrese el nombre
</div>
</div>
UPDATE 2:
I will explain it better, I have two fields that matter to me that are compulsory "Matricula" and "Nombre Completo", when I am filling out the third field I do not get the validation message, this is the code I have, will I be doing something wrong?
function validate(field) {
const input = field;
if (!input.value || input.value.length === 0) {
input.classList.add('invalid');
} else {
input.classList.remove('invalid');
}
}
input {
display: block;
}
.validation-message {
display: none;
}
input.validateable.invalid + .validation-message {
display: block;
color: red;
}
<div class="form-group">
<label class="required-field" name="matricula" for="ticketIdAppliInput">Matrícula:</label>
<input onchange="validate(this)" maxlength="9" id="ticketIdAppliInput" type="text" name="matricula" onkeypress="if (isNaN(String.fromCharCode(event.keyCode))) return false;" class="form-control form-control-user validateable"/>
<div class="validation-message">
Verifique la información nuevamente, ingrese la matricula</div>
</div>
<div class="form-group">
<label class="required-field" name="nombre" for="ticketNameAppliInput">Nombre completo:</label>
<input onchange="validate(this)" maxlength="100" id="ticketNameAppliInput" type="text" name="nombre" class="form-control form-control-user validateable" />
<div class="validation-message">
Verifique la información nuevamente, ingrese el nombre
</div>
</div>
<div class="form-group">
<label class="required-field" name="email" for="ticketEmailAppliInput">Email:</label>
<input onchange="validate(this)" maxlength="100" id="ticketEmailAppliInput" type="email" name="email" class="form-control form-control-user validateable" />
<div class="validation-message">
Verifique la información nuevamente, ingrese el correo electronico
</div>
</div>
To show a validation message under the field you need a element to display it.
It could be any div, span or whatever you want.
In my example i will use a span to demonstrate how it works:
<input onchange="validate();" type="text" class="validateable" validation-pattern="[0-9]*" />
<div class="validation-message">Only numbers are allowed in this field!</div>
now in the js code we just have to validate for the pattern and set a input to invalid if it does not match the pattern:
function validate(){
const validateables = document.getElementsByClassName('validateable');
Array.prototype.forEach.call(validateables, input => {
const pattern = input.getAttribute('validation-pattern');
if(!input.value.match('^' + pattern + '$')){
input.classList.add('invalid');
} else {
input.classList.remove('invalid');
}
});
}
and the css to display validation text only if invalid:
.validation-message {
display: none;
}
input.validateable.invalid + .validation-message{
display: block;
color: red;
}
What this code does:
The JS function looks for every input with the class "validateable" and iterates over them. Each element should have an attribute with an validation pattern validation-pattern="[0-9]*" Now the function checks, if the value of the input matches the pattern and add a class invalid to the input or removes it.
In the css i defined an invisible div validation-message but if the element bevor this div is an validateable input field, that is invalid, the div will be displayed and you can see the validation message.
Working fidle:
https://jsfiddle.net/h687eomf/
UPDATE:
in your case, you just want to validate the field, that you are changing, have a look at my changed example fidle:
https://jsfiddle.net/h687eomf/2/
UPDATE 2:
A try to fix your snippet, assuming that a field is valid when its value is not empty and invalid if the value is empty:
function validate(field) {
const input = field;
if (!input.value || input.value.length === 0) {
input.classList.add('invalid');
} else {
input.classList.remove('invalid');
}
}
input {
display: block;
}
.validation-message {
display: none;
}
input.validateable.invalid + .validation-message {
display: block;
color: red;
}
<div class="form-group">
<label class="required-field" name="matricula" for="ticketIdAppliInput">Matrícula:</label>
<input onchange="validate(this)" maxlength="9" required="required" id="ticketIdAppliInput" type="text" name="matricula" onkeypress="if (isNaN(String.fromCharCode(event.keyCode))) return false;" class="form-control form-control-user validateable"/>
<div class="validation-message">
Verifique la información nuevamente, ingrese la matricula</div>
</div>
<div class="form-group">
<label class="required-field" name="nombre" for="ticketNameAppliInput">Nombre completo:</label>
<input onchange="validate(this)" maxlength="100" id="ticketNameAppliInput" type="text" name="nombre" class="form-control form-control-user validateable" />
<div class="validation-message">
Verifique la información nuevamente, ingrese el nombre
</div>
</div>

form validation message (dynamic)

Is there a way to dynamically tell which .input has yet to be entered? In the code below you can see that if I enter out of order, the #message
only counts how many inputs have been populated and displays the message listed in order under numValid == 1, 2, 3, etc.
Can the code be changed to dynamically display a message for the .inputs that have not been populated?
*****Example: if I type in the Last Name and Student ID field, the message will either tell me to enter in the First Name or City field, etc. until they are all populated and the last validation (success message) is displayed*****
$("#form input").keyup(function() {
var numValid = 0;
$("#form input[required]").each(function() {
if (this.validity.valid) {
numValid++;
}
});
var progress = $("#progress"),
progressMessage = $("#message");
if (numValid == 1) {
progress.attr("value", "25");
progressMessage.text("Please Enter the First Name.");
}
if (numValid == 2) {
progress.attr("value", "50");
progressMessage.text("Please Enter the Last Name.");
}
if (numValid == 3) {
progress.attr("value", "75");
progressMessage.text("Please Enter a City.");
}
if (numValid == 4) {
progress.attr("value", "100");
progressMessage.text("You're done, post!");
}
});
#mainformdiv {
margin-left: auto;
margin-right: auto;
width: 500px;
border: 1px solid;
border-radius: 10px;
}
#form {
padding: 20px;
}
#progress {
width: 460px;
height: 25px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="mainformdiv">
<form id="form">
<div id="progressdiv">
<progress max="100" value="0" id="progress"></progress>
<div id="message">Progress Message...</div>
</div>
<div class="input">
<label for="userid">Student ID</label><br>
<input id="userid" required="required" type="text">
</div>
<div class="input">
<label for="firstname">First Name</label><br>
<input id="firstname" required="required" type="text">
</div>
<div class="input">
<label for="lastname">Last Name</label><br>
<input id="lastname" required="required" type="text">
</div>
<div class="input">
<label for="city">City</label><br>
<input id="city" required="required" type="text"></br>
</div>
</form>
</div>
Easy to accomplish, just iterate over all of the required fields, and join their ids into a string. If you want to display a nicer looking name, then just map the IDs to an object first.
$("#form input").keyup(function() {
var numValid = 0;
$("#form input[required]").each(function() {
if (this.validity.valid) {
numValid++;
}
});
var progress = $("#progress"),
progressMessage = $("#message");
const invalidInputs = Array.from(document.querySelectorAll('#form input[required]'))
.filter(input => !input.validity.valid)
.map(input => input.id);
progress.attr("value", numValid * 25);
if (numValid == 4) {
progressMessage.text("You're done, post!");
} else {
progressMessage.text('Please fill out the following fields: ' + invalidInputs.join(', '));
}
});
#mainformdiv {
margin-left: auto;
margin-right: auto;
width: 500px;
border: 1px solid;
border-radius: 10px;
}
#form {
padding: 20px;
}
#progress {
width: 460px;
height: 25px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="mainformdiv">
<form id="form">
<div id="progressdiv">
<progress max="100" value="0" id="progress"></progress>
<div id="message">Progress Message...</div>
</div>
<div class="input">
<label for="userid">Student ID</label><br>
<input id="userid" required="required" type="text">
</div>
<div class="input">
<label for="firstname">First Name</label><br>
<input id="firstname" required="required" type="text">
</div>
<div class="input">
<label for="lastname">Last Name</label><br>
<input id="lastname" required="required" type="text">
</div>
<div class="input">
<label for="city">City</label><br>
<input id="city" required="required" type="text"></br>
</div>
</form>
</div>

Categories

Resources