I've been getting back into Javascript lately, and I've created this simple form validation as practice. I'm wondering what the best way to go about something, logically would be. Take a look at this code:
var regName = /^[A-Za-z]+$/;
var regEmail = /^[A-Za-z]+$/;
var regUserName = /^[A-Za-z]+$/;
var regPassword = /^[A-Za-z]+$/;
//span tags multiply when you keep hitting the submit button. .textContent doesn't seem to work, and even if it did it's kind of a cheap work around because the tags will still be there, you just wont see them. I need to check if the tag exists (before the if statement) and if it does, remove it.
var validate = {
validateName: function() {
var fName = document.getElementById('fName');
var nameContainer = document.querySelector('#nameContainer');
var infoSpan = document.createElement('span');
nameContainer.appendChild(infoSpan);
fName.classList.remove('errorBorder');
if (fName.value.match(regName)) {
console.log('Name Valid');
infoSpan.classList.add('checkmark');
infoSpan.innerHTML = '*checkmark*';
} else if(fName.value === '') {
console.log('input is empty');
} else {
console.log('Name Invalid');
fName.classList.add('errorBorder');
infoSpan.classList.add('error');
infoSpan.innerHTML = '*invalid input';
}
},
validateEmail: function() {
var fEmail = document.getElementById('fEmail');
var emailContainer = document.querySelector('#emailContainer');
var infoSpan = document.createElement('span');
emailContainer.appendChild(infoSpan);
fEmail.classList.remove('errorBorder');
if (fEmail.value.match(regEmail)) {
console.log('Email Valid');
infoSpan.classList.add('checkmark');
infoSpan.textContent = '*checkmark*';
} else {
console.log('Email Invalid');
fEmail.classList.add('errorBorder');
infoSpan.classList.add('error');
infoSpan.textContent = '*invalid input';
}
},
validateUserName: function() {
var fUserName = document.getElementById('fUserName');
var userNameContainer = document.querySelector('#userNameContainer');
var infoSpan = document.createElement('span');
userNameContainer.appendChild(infoSpan);
fUserName.classList.remove('errorBorder');
if (fUserName.value.match(regUserName)) {
console.log('User Name Valid');
infoSpan.classList.add('checkmark');
infoSpan.textContent = '*checkmark*';
} else {
console.log('User Name Invalid');
fUserName.classList.add('errorBorder');
infoSpan.classList.add('error');
infoSpan.textContent = '*invalid input';
}
},
validatePassword: function() {
var fPassword = document.getElementById('fPassword');
var passwordContainer = document.querySelector('#passwordContainer');
var infoSpan = document.createElement('span');
passwordContainer.appendChild(infoSpan);
fPassword.classList.remove('errorBorder');
if (fPassword.value.match(regPassword)) {
console.log('Passowrd Valid');
infoSpan.classList.add('checkmark');
infoSpan.textContent = '*checkmark*';
} else {
console.log('Passowrd Invalid');
fPassword.classList.add('errorBorder');
infoSpan.classList.add('error');
infoSpan.textContent = '*invalid input';
}
}
};
function onSubmit() {
validate.validateName();
validate.validateEmail();
validate.validateUserName();
validate.validatePassword();
}
<form onsubmit="return false">
<div id="nameContainer">
<label>Full Name: </label>
<input type="text" id="fName" />
</div>
<div id="emailContainer">
<label>Email: </label>
<input type="text" id="fEmail" />
</div>
<div id="userNameContainer">
<label>User Name: </label>
<input type="text" id="fUserName" />
</div>
<div id="passwordContainer">
<label>Password: </label>
<input type="password" id="fPassword" />
</div>
<br />
<input type="submit" value="submit" onclick="onSubmit()" />
</form>
If you take a look at my my code, you'll see there are 4 fields and a submit button. Right now the JavaScript code just returns either "checkmark" or "invalid input" inside tags next tot he input fields depending on if the input fields are populated or not.
The issues I'm having is, if you hit the submit button more than once (running all the functions agani), the
I would like only the most recent sets of span tags to show. Or in other words, before inserting the span tags, to check if they exist in the DOM and delete them if they do.
I updated the plaker and added a function that cleans all errors before submitting. That was missing in your code: https://plnkr.co/edit/tIvl5rplqAP53ylzLLtf?p=preview
function cleanErrors() {
var allErrors = document.querySelectorAll('form input + span');
for (var i=0; i < allErrors.length; i++) {
console.log('error',allErrors[i]);
allErrors[i].parentNode.removeChild(allErrors[i]);
}
}
function onSubmit() {
cleanErrors();
validate.validateName();
validate.validateEmail();
validate.validateUserName();
validate.validatePassword();
}
What I would do is assign the info div an ID, that way you can first try to get an existing infospan. Then check if it exists, if it does just use it instead, if it doesn't create it.
//var regName = /^[A-Za-z]+ [A-Za-z]+$/;
//var regEmail = /\w{1-20}#\w{1-10}.\w{2-3}/;
//var regUserName = /^[A-Za-z0-9_-]{1,20}$/;
//var regPassword = /^[A-Za-z0-9!##$%^&*()_-]{6,20}$/;
var regName = /^[A-Za-z]+$/;
var regEmail = /^[A-Za-z]+$/;
var regUserName = /^[A-Za-z]+$/;
var regPassword = /^[A-Za-z]+$/;
//span tags multiply when you keep hitting the submit button. .textContent doesn't seem to work, and even if it did it's kind of a cheap work around because the tags will still be there, you just wont see them. I need to check if the tag exists (before the if statement) and if it does, remove it.
var validate = {
validateName: function() {
var fName = document.getElementById('fName');
var nameContainer = document.querySelector('#nameContainer');
var infoSpan = document.getElementById('fNameInfo');
if (!infoSpan) {
infoSpan = document.createElement('span');
infoSpan.id = 'fNameInfo';
nameContainer.appendChild(infoSpan);
}
fName.classList.remove('errorBorder');
infoSpan.classList.remove('checkmark');
infoSpan.classList.remove('error');
if (fName.value.match(regName)) {
console.log('Name Valid');
infoSpan.classList.add('checkmark');
infoSpan.innerHTML = '*checkmark*';
} else if(fName.value === '') {
console.log('input is empty');
} else {
console.log('Name Invalid');
fName.classList.add('errorBorder');
infoSpan.classList.add('error');
infoSpan.innerHTML = '*invalid input';
}
},
validateEmail: function() {
var fEmail = document.getElementById('fEmail');
var emailContainer = document.querySelector('#emailContainer');
var infoSpan = document.getElementById('fEmailInfo');
if (!infoSpan) {
infoSpan = document.createElement('span');
infoSpan.id = 'fEmailInfo';
emailContainer.appendChild(infoSpan);
}
fEmail.classList.remove('errorBorder');
infoSpan.classList.remove('checkmark');
infoSpan.classList.remove('error');
if (fEmail.value.match(regEmail)) {
console.log('Email Valid');
infoSpan.classList.add('checkmark');
infoSpan.textContent = '*checkmark*';
} else {
console.log('Email Invalid');
fEmail.classList.add('errorBorder');
infoSpan.classList.add('error');
infoSpan.textContent = '*invalid input';
}
},
validateUserName: function() {
var fUserName = document.getElementById('fUserName');
var userNameContainer = document.querySelector('#userNameContainer');
var infoSpan = document.getElementById('fUserNameInfo');
if (!infoSpan) {
infoSpan = document.createElement('span');
infoSpan.id = 'fUserNameInfo';
userNameContainer.appendChild(infoSpan);
}
fUserName.classList.remove('errorBorder');
infoSpan.classList.remove('checkmark');
infoSpan.classList.remove('error');
if (fUserName.value.match(regUserName)) {
console.log('User Name Valid');
infoSpan.classList.add('checkmark');
infoSpan.textContent = '*checkmark*';
} else {
console.log('User Name Invalid');
fUserName.classList.add('errorBorder');
infoSpan.classList.add('error');
infoSpan.textContent = '*invalid input';
}
},
validatePassword: function() {
var fPassword = document.getElementById('fPassword');
var passwordContainer = document.querySelector('#passwordContainer');
var infoSpan = document.getElementById('fPasswordInfo');
if (!infoSpan) {
infoSpan = document.createElement('span');
infoSpan.id = 'fPasswordInfo';
passwordContainer.appendChild(infoSpan);
}
fPassword.classList.remove('errorBorder');
infoSpan.classList.remove('checkmark');
infoSpan.classList.remove('error');
if (fPassword.value.match(regPassword)) {
console.log('Passowrd Valid');
infoSpan.classList.add('checkmark');
infoSpan.textContent = '*checkmark*';
} else {
console.log('Passowrd Invalid');
fPassword.classList.add('errorBorder');
infoSpan.classList.add('error');
infoSpan.textContent = '*invalid input';
}
}
};
function onSubmit() {
validate.validateName();
validate.validateEmail();
validate.validateUserName();
validate.validatePassword();
}
/* Styles go here */
label, span {
font-family: sans-serif;
}
label {
font-size: 14px;
}
form div {
margin: 10px 0;
}
label {
display: inline-block;
width: 85px;
}
.errorBorder {
border: thin red solid;
}
span.error {
color: red;
font-size: 12px;
display: inline-block;
margin-left: 10px;
}
span.checkmark {
color: green;
font-weight: bold;
}
<form onsubmit="return false">
<div id="nameContainer">
<label>Full Name: </label>
<input type="text" id="fName" />
</div>
<div id="emailContainer">
<label>Email: </label>
<input type="text" id="fEmail" />
</div>
<div id="userNameContainer">
<label>User Name: </label>
<input type="text" id="fUserName" />
</div>
<div id="passwordContainer">
<label>Password: </label>
<input type="password" id="fPassword" />
</div>
<br />
<input type="submit" value="submit" onclick="onSubmit()" />
</form>
With the HTML structure that you have, the simplest way to know if there is a span element just after the current input element that is being validated is to just check the nextElementSibling of the input element to see if it is a span. If it is, then you need to remove the nextElementSibling and if not, you can add it.
For example, in your first validation:
var fName = document.getElementById('fName');
// .getElementById() is faster than .querySelector() when looking for id's
var nameContainer = document.getElementById('nameContainer');
// Is the next element sibling of the field a span?
if(nameContainer.nextElementSibling.nodeName === "SPAN"){
// span already exists - remove it
nameContainer.parentNode.removeChild(nameContainer.nextElementSibling);
} else {
// span does not exist - create and add it
var infoSpan = document.createElement('span');
nameContainer.appendChild(infoSpan);
}
Having said that, this is entirely unnecessary and hinders performance because you are modifying the DOM over and over.
Since you need a span no matter what, just create them statically in the HTML and then just update their textContent (don't use .innerHTML unless you have HTML to be parsed).
var regName = /^[A-Za-z]+$/;
var regEmail = /^[A-Za-z]+$/;
var regUserName = /^[A-Za-z]+$/;
var regPassword = /^[A-Za-z]+$/;
var validate = {
validateName: function() {
var fName = document.getElementById('fName');
var nameContainer = document.querySelector('#nameContainer');
var infoSpan = document.getElementById('nameInfo');
fName.classList.remove('errorBorder');
if (fName.value.match(regName)) {
console.log('Name Valid');
infoSpan.classList.add('checkmark');
infoSpan.textContent = '*checkmark*';
} else if(fName.value === '') {
console.log('input is empty');
} else {
console.log('Name Invalid');
fName.classList.add('errorBorder');
infoSpan.classList.add('error');
infoSpan.textContent = '*invalid input';
}
},
validateEmail: function() {
var fEmail = document.getElementById('fEmail');
var emailContainer = document.querySelector('#emailContainer');
var infoSpan = document.getElementById('emailInfo');
fEmail.classList.remove('errorBorder');
if (fEmail.value.match(regEmail)) {
console.log('Email Valid');
infoSpan.classList.add('checkmark');
infoSpan.textContent = '*checkmark*';
} else {
console.log('Email Invalid');
fEmail.classList.add('errorBorder');
infoSpan.classList.add('error');
infoSpan.textContent = '*invalid input';
}
},
validateUserName: function() {
var fUserName = document.getElementById('fUserName');
var userNameContainer = document.querySelector('#userNameContainer');
var infoSpan = document.getElementById('userNameInfo');
fUserName.classList.remove('errorBorder');
if (fUserName.value.match(regUserName)) {
console.log('User Name Valid');
infoSpan.classList.add('checkmark');
infoSpan.textContent = '*checkmark*';
} else {
console.log('User Name Invalid');
fUserName.classList.add('errorBorder');
infoSpan.classList.add('error');
infoSpan.textContent = '*invalid input';
}
},
validatePassword: function() {
var fPassword = document.getElementById('fPassword');
var passwordContainer = document.querySelector('#passwordContainer');
var infoSpan = document.getElementById('passwordInfo');
fPassword.classList.remove('errorBorder');
if (fPassword.value.match(regPassword)) {
console.log('Passowrd Valid');
infoSpan.classList.add('checkmark');
infoSpan.textContent = '*checkmark*';
} else {
console.log('Passowrd Invalid');
fPassword.classList.add('errorBorder');
infoSpan.classList.add('error');
infoSpan.textContent = '*invalid input';
}
}
};
function onSubmit() {
validate.validateName();
validate.validateEmail();
validate.validateUserName();
validate.validatePassword();
}
/* Styles go here */
label, span {
font-family: sans-serif;
}
label {
font-size: 14px;
}
form div {
margin: 10px 0;
}
label {
display: inline-block;
width: 85px;
}
.errorBorder {
border: thin red solid;
}
span.error {
color: red;
font-size: 12px;
display: inline-block;
margin-left: 10px;
}
span.checkmark {
color: green;
font-weight: bold;
}
<form onsubmit="return false">
<div id="nameContainer">
<label>Full Name: </label>
<input type="text" id="fName"><span id="nameInfo"></span>
</div>
<div id="emailContainer">
<label>Email: </label>
<input type="text" id="fEmail"><span id="emailInfo"></span>
</div>
<div id="userNameContainer">
<label>User Name: </label>
<input type="text" id="fUserName"><span id="userNameInfo"></span>
</div>
<div id="passwordContainer">
<label>Password: </label>
<input type="password" id="fPassword"><span id="passwordInfo"></span>
</div>
<br />
<input type="submit" value="submit" onclick="onSubmit()">
</form>
You may also want to reconsider this entire design given that each of your validation functions is essentially the same, except for the regular expression that it uses to determine validity. Additionally, you could also just use the HTML5 form fields that have built-in validation or a full API for you to work from.
// Do all event wiring in JavaScript, not with HTML event attributes
// And, form validation should be done on the form's submit event and
// the form submission should be cancelled via the event object that
// is automatically passed to the function
document.querySelector("form").addEventListener("submit", function(evt){
// Store regular expressions in an object
var regs = {
regName : /^[A-Za-z]+$/,
regEmail : /^[A-Za-z]+$/,
regUserName : /^[A-Za-z]+$/,
regPassword : /^[A-Za-z]+$/
};
var valid = true; // Set up variable to track any errors
// Gather up all the fields to be validated into an array.
var fieldsToValidate = Array.prototype.slice.call(document.querySelectorAll(".validate"));
// Loop over each of the fields to be validated
fieldsToValidate.forEach(function(field, index){
var message = "";
var infoSpan = field.nextElementSibling;
// Test the field against the corresponding regular expression in the object
if(field.value.match(regs[Object.keys(regs)[index]])){
message = "*checkmark*";
infoSpan.classList.remove("error");
infoSpan.classList.add("checkmark");
} else {
valid = false;
message = "*error*";
infoSpan.classList.remove("checkmark");
infoSpan.classList.add("error");
}
infoSpan.textContent = message;
});
// If there were any errors, prevent the form from being submitted
if(!valid){ evt.preventDefault(); }
});
label, span { font-family: sans-serif; }
label { font-size: 14px; display: inline-block; width: 85px; }
form div { margin: 10px 0; }
.error {
color: red;
font-size: 12px;
display: inline-block;
margin-left: 10px;
border: thin red solid;
}
.checkmark {
color: green;
font-weight: bold;
}
<form>
<div>
<label>Full Name: </label>
<input type="text" id="fName" class="validate"><span id="nameInfo"></span>
</div>
<div>
<label>Email: </label>
<input type="text" id="fEmail" class="validate"><span id="emailInfo"></span>
</div>
<div>
<label>User Name: </label>
<input type="text" id="fUserName" class="validate"><span id="userNameInfo"></span>
</div>
<div>
<label>Password: </label>
<input type="password" id="fPassword" class="validate"><span id="passwordInfo"></span>
</div>
<div><input type="submit" value="submit"></div>
</form>
Related
When click on the submit button, I want to make sure it can detect if the user correctly entered the forms through the functions below, if user did not enter correctly it can stop the form from being submit.
What should I include in my AllValidate function?*
<button name="regbtn" id="register_btn" class="reg_btn" type="submit" onclick="AllValidate()">Register</button>
function addressValidate()
{
var address = document.getElementById("reg_add").value;
var space = /^\s*$/;
var flag = true;
if(address.match(space))
{
document.getElementById("add_error").innerHTML = "Address is required.";
document.getElementById("reg_add").style.border = "2px solid red";
flag = true;
}
else
{
document.getElementById("add_error").innerHTML = "";
document.getElementById("reg_add").style.border = "2px solid #f0f0f0";
flag = false;
}
return flag;
}
function phoneValidate()
{
var phoneNo = document.getElementById("reg_phone").value;
var pattern = /[0-9]{3}-[0-9]{4}-[0-9]{4}/;
var space = /^\s*$/;
var flag = true;
if(phoneNo.match(space))
{
document.getElementById("phone_error").innerHTML = "Phone number is required.";
document.getElementById("reg_phone").style.border = "2px solid red";
flag = true;
}
else if(phoneNo.match(pattern))
{
document.getElementById("phone_error").innerHTML = "";
document.getElementById("reg_phone").style.border = "2px solid #f0f0f0";
flag = false;
}
else
{
document.getElementById("phone_error").innerHTML = "Please enter a valid phone number.";
document.getElementById("reg_phone").style.border = "2px solid red";
flag = true;
}
return flag;
}
AllValidate()
{
}
First you have to edit the submit button as follows
<button name="regbtn" id="register_btn" class="reg_btn" type="submit" onclick="return AllValidate()">Register</button>
Then your AllValidate() function follows
function AllValidate(){
return (addressValidate() && phoneValidate());
}
use that way, with HTML5 auto validation
use attribute required
use attribute pattern ( you can also use input type="tel")
sample code
// personnalize your error message
const myForm = document.forms['my-form']
myForm.reg_phone.oninvalid=_=>
{
let msg = (myForm.reg_phone.value.trim() === '')
? 'Phone number is required.'
: 'Please enter a valid phone number.'
myForm.reg_phone.setCustomValidity(msg)
}
// just to verify input...
myForm.onsubmit = evt =>
{
evt.preventDefault() // just for test here (disable submit)
// shwo values
console.clear()
console.log( 'name :' , myForm.reg_name.value )
console.log( 'address :' , myForm.reg_add.value )
console.log( 'Phone :' , myForm.reg_phone.value )
}
form {
display: flex;
flex-direction: column;
width: 18em;
}
label {
display: block;
margin-top: .7em;
}
label * {
vertical-align: baseline;
}
label input,
label textarea {
display: block;
float: right;
font-size:1.2em;
padding: .2em;
}
label input {
width: 9em;
}
button {
margin: 2em;
font-weight: bold;
}
<form action="..." name="my-form">
<label>
name :
<input type="text" name="reg_name" required>
</label>
<label>
address :
<textarea name="reg_add" rows="4" required placeholder="address"></textarea>
</label>
<label>
Phone :
<input type="text" name="reg_phone" required pattern="\d{3}-\d{4}-\d{4}" placeholder="___-____-____">
</label>
<button type="submit">Register</button>
</form>
Now the button is activated if one of the fields is valid.
As I understand it, it is necessary to select all errors, and if there are more than 1 errors - disabled
Code validation
var forms = document.querySelectorAll('.validate');
for (var i = 0; i < forms.length; i++) {
forms[i].setAttribute('novalidate', true);
forms[i].lastElementChild.setAttribute('disabled', true);
}
// function has error
var hasError = function(field) {
if (field.disabled || field.type === 'file' || field.type === 'reset' || field.type === 'submit' || field.type === 'button') return;
var validity = field.validity;
if (validity.valid) {
return;
}
if (validity.valueMissing) {
return 'This is a required field';
}
if (validity.typeMismatch) {
// URL
if (field.type === 'url') {
return 'There should be a link';
}
}
if (validity.tooShort) {
return 'Must be from ' + field.getAttribute('minLength') + ' to ' + field.getAttribute('maxLength') + ' characters';
}
if (validity.tooLong) {
return 'Must be from ' + field.getAttribute('minLength') + ' to ' + field.getAttribute('maxLength') + ' characters';
}
return 'Error';
};
// function show error
var showError = function(field, error) {
field.classList.add('error');
var id = field.id || field.name;
if (!id) return;
var message = field.form.querySelector('.error-message#error-for-' + id);
if (!message) {
message = document.createElement('div');
message.className = 'error-message';
message.id = 'error-for-' + id;
field.parentNode.insertBefore(message, field.nextSibling);
}
field.setAttribute('aria-describedby', 'error-for-' + id);
message.innerHTML = error;
message.style.display = 'block';
message.style.visibility = 'visible';
};
// function remove error
var removeError = function(field) {
field.classList.remove('error');
field.removeAttribute('aria-describedby');
var id = field.id || field.name;
if (!id) return;
var message = field.form.querySelector('.error-message#error-for-' + id + '');
if (!message) return;
message.innerHTML = '';
message.style.display = 'none';
message.style.visibility = 'hidden';
};
// function check field
function checkInput(event) {
if (!event.target.form.classList.contains('validate')) return;
var error = hasError(event.target);
if (error) {
event.target.parentElement.parentElement.lastElementChild.setAttribute('disabled', true);
showError(event.target, error);
return;
}
removeError(event.target);
event.target.parentElement.parentElement.lastElementChild.removeAttribute('disabled');
}
// function check fields
function validationForm(event) {
if (!event.target.classList.contains('validate')) return;
var fields = event.target.elements;
var error, hasErrors;
for (var i = 0; i < fields.length; i++) {
error = hasError(fields[i]);
if (error) {
showError(fields[i], error);
if (!hasErrors) {
hasErrors = fields[i];
}
}
}
if (hasErrors) {
event.preventDefault();
hasErrors.focus();
}
}
document.addEventListener('input', checkInput);
document.addEventListener('submit', validationForm);
input {
display: inline-block;
font-size: 1em;
margin-bottom: 5px;
padding: 0.25em 0.5em;
width: 100%;
}
.button[disabled],
.button[disabled]:active,
.button[disabled]:focus,
.button[disabled]:hover {
border-color: #ccc;
background-color: #ccc;
}
.button {
background-color: #0088cc;
border: 1px solid #0088cc;
color: #ffffff;
display: inline-block;
font-size: 0.9375em;
font-weight: normal;
line-height: 1.2;
margin-right: 0.3125em;
margin-bottom: 0.3125em;
padding: 0.5em 0.6875em;
width: auto;
}
.button:active,
.button:focus,
.button:hover {
background-color: #005580;
border-color: #005580;
color: #ffffff;
text-decoration: none;
}
/**
* Errors
*/
.error {
border-color: red;
}
.error-message {
color: red;
font-size: 1rem;
margin-bottom: 15px;
}
<form class="validate">
<div>
<input type="text" minlength="3" maxlength="40" name="name" placeholder="Enter name" required>
</div>
<div>
<input type="url" name="url" pattern="^(?:(?:https?|HTTPS?|ftp|FTP):\/\/)(?:\S+(?::\S*)?#)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-zA-Z\u00a1-\uffff0-9]-*)*[a-zA-Z\u00a1-\uffff0-9]+)(?:\.(?:[a-zA-Z\u00a1-\uffff0-9]-*)*[a-zA-Z\u00a1-\uffff0-9]+)*(?:\.(?:[a-zA-Z\u00a1-\uffff]{2,}))\.?)(?::\d{2,5})?(?:[/?#]\S*)?$"
placeholder="Enter url" required>
</div>
<input type="submit" class="button" value="Submit">
</form>
<br>
<form class="validate">
<div>
<input type="user" minlength="4" maxlength="40" id="user" placeholder="Enter user" required>
</div>
<div>
<input type="position" minlength="5" maxlength="50" id="position" placeholder="Enter position" required>
</div>
<input type="submit" class="button" value="Submit">
</form>
I guess this is the problem part of the code
// function check field
function checkInput(event) {
if (!event.target.form.classList.contains('validate')) return;
var error = hasError(event.target);
if (error) {
event.target.parentElement.parentElement.lastElementChild.setAttribute('disabled', true);
showError(event.target, error);
return;
}
removeError(event.target);
event.target.parentElement.parentElement.lastElementChild.removeAttribute('disabled');
}
I expect the button to activate only if both fields have passed validation.
But now the button is activated if one of the fields is valid
You would need to update your check function. Current function is just Validating input that you are changing as you have added change input listener. you would need to add loop that Validate other fields for error.
// function check field
function checkInput(event) {
if (!event.target.form.classList.contains('validate')) return;
var error = hasError(event.target);
if (error) {
event.target.parentElement.parentElement.lastElementChild.setAttribute('disabled', true);
showError(event.target, error);
return;
}
//To Check All fields If There is still an error
var fields = event.target.parentElement.parentElement.elements;
for (var i = 0; i < fields.length; i++) {
error = hasError(fields[i]);
if (error) {
removeError(event.target);
event.target.parentElement.parentElement.lastElementChild.setAttribute('disabled', true);
return;
}
}
removeError(event.target);
event.target.parentElement.parentElement.lastElementChild.removeAttribute('disabled');
}
The solution:
var forms = document.querySelectorAll('.validate');
for (var i = 0; i < forms.length; i++) {
forms[i].setAttribute('novalidate', true);
forms[i].lastElementChild.setAttribute('disabled', true);
}
// function has error
var hasError = function(field) {
if (field.disabled || field.type === 'file' || field.type === 'reset' || field.type === 'submit' || field.type === 'button') return;
var validity = field.validity;
if (validity.valid) {
return;
}
if (validity.valueMissing) {
return 'This is a required field';
}
if (validity.typeMismatch) {
// URL
if (field.type === 'url') {
return 'There should be a link';
}
}
if (validity.tooShort) {
return 'Must be from ' + field.getAttribute('minLength') + ' to ' + field.getAttribute('maxLength') + ' characters';
}
if (validity.tooLong) {
return 'Must be from ' + field.getAttribute('minLength') + ' to ' + field.getAttribute('maxLength') + ' characters';
}
return 'Error';
};
// function show error
var showError = function(field, error) {
field.classList.add('error');
var id = field.id || field.name;
if (!id) return;
var message = field.form.querySelector('.error-message#error-for-' + id);
if (!message) {
message = document.createElement('div');
message.className = 'error-message';
message.id = 'error-for-' + id;
field.parentNode.insertBefore(message, field.nextSibling);
}
field.setAttribute('aria-describedby', 'error-for-' + id);
message.innerHTML = error;
message.style.display = 'block';
message.style.visibility = 'visible';
};
// function remove error
var removeError = function(field) {
field.classList.remove('error');
field.removeAttribute('aria-describedby');
var id = field.id || field.name;
if (!id) return;
var message = field.form.querySelector('.error-message#error-for-' + id + '');
if (!message) return;
message.innerHTML = '';
message.style.display = 'none';
message.style.visibility = 'hidden';
};
// function check field
function checkInput(event) {
if (!event.target.form.classList.contains('validate')) return;
var error = hasError(event.target);
if (error) {
event.target.parentElement.parentElement.lastElementChild.setAttribute('disabled', true);
showError(event.target, error);
return;
}
//To Check All fields If There is still an error
var fields = event.target.parentElement.parentElement.elements;
for (var i = 0; i < fields.length; i++) {
error = hasError(fields[i]);
if (error) {
removeError(event.target);
event.target.parentElement.parentElement.lastElementChild.setAttribute('disabled', true);
return;
}
}
removeError(event.target);
event.target.parentElement.parentElement.lastElementChild.removeAttribute('disabled');
}
// function check fields
function validationForm(event) {
if (!event.target.classList.contains('validate')) return;
var fields = event.target.elements;
var error, hasErrors;
for (var i = 0; i < fields.length; i++) {
error = hasError(fields[i]);
if (error) {
showError(fields[i], error);
if (!hasErrors) {
hasErrors = fields[i];
}
}
}
if (hasErrors) {
event.preventDefault();
hasErrors.focus();
}
}
document.addEventListener('input', checkInput);
document.addEventListener('submit', validationForm);
input {
display: inline-block;
font-size: 1em;
margin-bottom: 5px;
padding: 0.25em 0.5em;
width: 100%;
}
.button[disabled],
.button[disabled]:active,
.button[disabled]:focus,
.button[disabled]:hover {
border-color: #ccc;
background-color: #ccc;
}
.button {
background-color: #0088cc;
border: 1px solid #0088cc;
color: #ffffff;
display: inline-block;
font-size: 0.9375em;
font-weight: normal;
line-height: 1.2;
margin-right: 0.3125em;
margin-bottom: 0.3125em;
padding: 0.5em 0.6875em;
width: auto;
}
.button:active,
.button:focus,
.button:hover {
background-color: #005580;
border-color: #005580;
color: #ffffff;
text-decoration: none;
}
/**
* Errors
*/
.error {
border-color: red;
}
.error-message {
color: red;
font-size: 1rem;
margin-bottom: 15px;
}
<form class="validate">
<div>
<input type="text" minlength="3" maxlength="40" name="name" placeholder="Enter name" required>
</div>
<div>
<input type="url" name="url" pattern="^(?:(?:https?|HTTPS?|ftp|FTP):\/\/)(?:\S+(?::\S*)?#)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-zA-Z\u00a1-\uffff0-9]-*)*[a-zA-Z\u00a1-\uffff0-9]+)(?:\.(?:[a-zA-Z\u00a1-\uffff0-9]-*)*[a-zA-Z\u00a1-\uffff0-9]+)*(?:\.(?:[a-zA-Z\u00a1-\uffff]{2,}))\.?)(?::\d{2,5})?(?:[/?#]\S*)?$"
placeholder="Enter url" required>
</div>
<input type="submit" class="button" value="Submit">
</form>
<br>
<form class="validate">
<div>
<input type="user" minlength="4" maxlength="40" id="user" placeholder="Enter user" required>
</div>
<div>
<input type="position" minlength="5" maxlength="50" id="position" placeholder="Enter position" required>
</div>
<input type="submit" class="button" value="Submit">
</form>
The reason for it not to work as expected is that you remove the disabled state if there's no error by calling
event.target.parentElement.parentElement.lastElementChild.removeAttribute('disabled');
but don't add the Attribute disabled if there is an error.
So if you leave the name input blank but add e.g. http://example.com the button is enabled as the URL triggered the removeAttribute() function.
As mplungjan suggested it might be better to just use required attribute.
I'm working on a web form with several textboxes and a submit button. When the submit button is clicked, I am supposed to verify that the required fields all have input and that the age field is only numeric. For example, the user can enter 56, but 56 years-old, shouldn't be accepted. If the user enters invalid input or leaves required fields blank, the border around the appropriate textboxes should turn red.
However, as my code is written now all the required fields turn red regardless of input. Any ideas how I can fix this and make the page follow the couple of rules I listed?
Most Recent Code
<html>
<head>
<title>Project 4</title>
<style type="text/css">
body {
background-color: black;
color: blue;
text-align: center;
border: 2px double blue;
}
</style>
</head>
<body>
<h1>Welcome to my Web Form!</h1>
<p>
Please fill out the following information.<br>
Please note that fields marked with an asterisk (*) are required.
</p>
<form name="myForm" id="myForm" onsubmit="return validateForm()">
*Last Name: <br>
<input type="text" id="lastname">
<br>
First Name: <br>
<input type="text" id="firstname">
<br>
*Hobbies (separate each hobby with a comma): <br>
<input type="text" id="hobbies">
<br>
Pets:
<div id="petsContainer">
<input type="text" id="pets">
<input type="button" id="addPet" value="Add Pet">
</div>
<br>
Children:
<div id="childContainer">
<input type="text" id="children">
<input type="button" id="addKid" value="Add Child">
</div>
<br>
*Address: <br>
<input type="text" id="address">
<br>
*Phone Number:<br>
<input type="text" id="phone">
<br>
*Age: <br>
<input type="text" id="age">
<br>
<input type="submit" value="Submit">
</form>
<script type="text/javascript">
var validatePhoneOnKeyUpAttached = false;
var validateLNameOnKeyUpAttached = false;
var validateHobbiesOnKeyUpAttached = false;
var validateAddressOnKeyUpAttached = false;
var validateAgeOnKeyUpAttached = false;
function validateForm() {
if(!validatePhoneOnKeyUpAttached) {
document.getElementById("phone").onkeyup = checkPhone;
validatePhoneOnKeyUpAttached = true;
}
else if(!validateLNameOnKeyUpAttached) {
document.getElementById("lastname").onkeyup = checkEmpty;
validateLNameOnKeyUpAttached = true;
}
else if(!validateHobbiesOnKeyUpAttached) {
document.getElementById("hobbies").onkeyup = checkEmpty;
validateHobbiesOnKeyUpAttached = true;
}
else if(!validateAddressOnKeyUpAttached) {
document.getElementById("address").onkeyup = checkEmpty;
validateAddressOnKeyUpAttached = true;
}
else if(!validateAgeOnKeyUpAttached) {
document.getElementById("age").onkeyup = checkEmpty;
document.getElementById("age").onkeyup = checkAge;
validateAgeOnKeyUpAttached = true;
}
return checkEmpty() && checkPhone() && checkAge();
}
function checkPhone() {
var phone = document.forms["myForm"]["phone"].value;
var phoneNum = phone.replace(/[^\d]/g, '');
if(phoneNum.length > 6 && phoneNum.length < 11) {
document.getElementById("phone").style.borderColor="transparent";
return true;
}
else if(phoneNum.length < 7 || phoneNum.length > 10) {
document.getElementById("phone").style.borderColor="red";
return false;
}
}
function checkEmpty() {
var lname = document.forms["myForm"]["lastname"].value;
var pNum = document.forms["myForm"]["phone"].value;
var hobs = document.forms["myForm"]["hobbies"].value;
var live = document.forms["myForm"]["address"].value;
var yr = document.forms["myForm"]["age"].value;
document.getElementById("lastname").style.borderColor = (lname == "") ? "red" : "transparent";
document.getElementById("hobbies").style.borderColor = (hobs == "") ? "red" : "transparent";
document.getElementById("phone").style.borderColor = (pNum == "") ? "red" : "transparent";
document.getElementById("address").style.borderColor = (live == "") ? "red" : "transparent";
document.getElementById("age").style.borderColor = (yr == "") ? "red" : "transparent";
}
function checkAge() {
var age = document.getElementById("age").value;
if(isNan(age)) {
return false;
}
else {
document.getElementById("age").style.borderColor="red";
return true;
}
}
document.getElementById("addPet").onclick=function() {
var div = document.getElementById("petsContainer");
var input = document.createElement("input");
input.type = "text";
input.name = "pats[]";
div.appendChild(document.createElement("br"));
div.appendChild(input);
}
document.getElementById("addKid").onclick=function() {
var div = document.getElementById("childContainer");
var input = document.createElement("input");
input.type = "text";
input.name = "child[]";
div.appendChild(document.createElement("br"));
div.appendChild(input);
}
</script>
</body>
</html>
The problem I'm currently having is that when I click the submit button, all the fields turn red for a split second, but then go back to the regular color and the input is erased. Any thoughts on how to fix this?
By including all of the borderColor="red" statements in a single code block, you're applying that style to all your inputs, even if only one of them failed validation. You need to separate out each statement so that it only applies to the individual field(s) that failed validation:
document.getElementById("lastname").style.borderColor = (lname == "") ? "red" : "transparent";
document.getElementById("phone").style.borderColor = (pNum == "") ? "red" : "transparent";
...
Also, I'm using the ternary operator ? : to clean up the code as well. These statements would replace the if-else block you've written.
I am using the following javascript functions in order to validate my form variables. Hope these will helpful for you.
var W3CDOM = (document.getElementsByTagName && document.createElement);
window.onload = function () {
document.forms[0].onsubmit = function () {
return validate()
}
}
function validate() {
validForm = true;
firstError = null;
errorstring = '';
var x = document.forms[0].elements;
for (var i = 0;i < x.length;i++) {
if (!x[i].value) {
validForm = false;
writeError(x[i], 'This field is required');
}
}
// This can be used to validate input type Email values
/* if (x['email'].value.indexOf('#') == -1) {
validForm = false;
writeError(x['email'],'This is not a valid email address');
}
*/
if (!W3CDOM)
alert(errorstring);
if (firstError)
firstError.focus();
return validForm;
}
function writeError(obj, message) {
validForm = false;
//if (obj.hasError) return false;
if (W3CDOM) {
obj.className += ' error';
obj.onchange = removeError;
var sp = document.createElement('span');
sp.className = 'error';
sp.appendChild(document.createTextNode(message));
obj.parentNode.appendChild(sp);
obj.hasError = sp;
} else {
errorstring += obj.name + ': ' + message + '\n';
obj.hasError = true;
}
if (!firstError)
firstError = obj;
return false;
}
function removeError() {
this.className = this.className.substring(0, this.className.lastIndexOf(' '));
this.parentNode.removeChild(this.hasError);
this.hasError = null;
this.onchange = null;
}
You can call the validations right after the form submission as given below.
<form name="loginForm" action="do.login" method="POST" class="form" onsubmit="return validate();">
I have a form validation on 3 required input fields: name, address and city.
I made this javascript:
function Validate(form) {
var error_name = "";
var error_address = "";
var error_city = "";
if (form.name.value.length == 0) {
form.name.style.border = "1px solid red"; /*optioneel */
form.name.style.backgroundColor = "#FFCCCC"; /* optioneel */
error_name = "Name cannot be left blank!";
}
if (form.address.value.length == 0) {
form.address.style.border = "1px solid red"; /*optioneel */
form.address.style.backgroundColor = "#FFCCCC"; /* optioneel */
error_address = "Address cannot be left blank!";
}
if (form.city.value.length == 0) {
form.city.style.border = "1px solid red"; /*optioneel */
form.city.style.backgroundColor = "#FFCCCC"; /* optioneel */
error_city = "City cannot be left blank!";
}
if (error_name.length > 0) {
document.getElementById("error_name").innerHTML = error_name ;
return false;
}
if (error_address.length > 0) {
document.getElementById("error_name").innerHTML = error_address ;
return false;
}
if (error_city.length > 0) {
document.getElementById("error_name").innerHTML = error_city ;
return false;
}
return true;
}
document.getElementById("aanmelden").onsubmit = function () {
return Validate(this);
};
And this is a piece of the form:
<div id="form" >
<h3>Aanmelding WIES Congres</h3>
<p class="legend">Deelnemer</p>
<fieldset class="input2" id="Deelnemer">
<label>Naam:</label>
<div id="error_name"></div>
<input type="text" name="name" maxlength="25" size="25">
<label class="right">Bedrijf:</label>
<input class="right" type="text" name="company" maxlength="25" size="25">
<br/>
<label>Adres:</label>
<div id="error_address"></div>
<input type="text" name="address" maxlength="25" size="25"> <br />
<label>Postcode:</label>
<input type="text" name="postalcode" maxlength="6" size="6"> <br />
<label class="right">Plaats:</label>
<div id="error_city"></div>
<input class="right" type="text" name="city" maxlength="25" size="25">
<label>Land</label>
<select name="country">
and so on----
As you can see in the form, the name error should occur above the name field, the address error above the address field and so on..
But this is not happening: all errors are shown above the name field, wether it is name, address or city error...
What do i do wrong?
It looks like all of your errors are targeting the same div : #error_name.
Try changing each one to target the appropriate div:
document.getElementById("error_name").innerHTML = error_name;
document.getElementById("error_address").innerHTML = error_address;
document.getElementById("error_city").innerHTML = error_city;
Also, some of your input names do not match their references. For example:
form.name should be form.form_name
form.address should be form.form_address
form.city should be form.form_city
In order to display all the errors at once (instead of just one per form submission) you'll need to remove all the return false; lines and put one conditional return at the end of the function. Also, you'll need a way to "clear" the errors after the user corrects blank inputs.
Here is the restructured function:
function Validate(form) {
// INITIALIZE VARIABLES
var error_name = "";
var error_address = "";
var error_city = "";
var valid = true;
// CHECK FOR BLANK INPUTS, SET ERROR MESSAGES
if (form.form_name.value.length == 0) {
error_name += "Name cannot be left blank!";
}
if (form.form_address.value.length == 0) {
error_address += "Address cannot be left blank!";
}
if (form.form_city.value.length == 0) {
error_city += "City cannot be left blank!";
}
// UPDATE ERROR MESSAGE DISPLAYS
document.getElementById("error_name").innerHTML = error_name;
document.getElementById("error_address").innerHTML = error_address;
document.getElementById("error_city").innerHTML = error_city;
// IF ERROR MESSAGE EXISTS, CHANGE STYLES AND SET VALID TO FALSE
// ELSE IF NO ERRORS, RESET STYLES
if (error_name.length > 0) {
form.form_name.style.border = "1px solid red";
form.form_name.style.backgroundColor = "#FFCCCC";
valid = false;
} else {
form.form_name.style.border = "none";
form.form_name.style.backgroundColor = "#FFFFFF";
}
if (error_address.length > 0) {
form.form_address.style.border = "1px solid red";
form.form_address.style.backgroundColor = "#FFCCCC";
valid = false;
} else {
form.form_address.style.border = "none";
form.form_address.style.backgroundColor = "#FFFFFF";
}
if (error_city.length > 0) {
form.form_city.style.border = "1px solid red";
form.form_city.style.backgroundColor = "#FFCCCC";
valid = false;
} else {
form.form_city.style.border = "none";
form.form_city.style.backgroundColor = "#FFFFFF";
}
// RETURN FORM VALIDITY (TRUE OR FALSE)
// "FALSE" STOPS THE FORM FROM SUBMITTING
return valid;
}
// CONFIGURE ONSUBMIT FUNCTION
document.getElementById("aanmelden").onsubmit = function () {
return Validate(this);
};
Here is a working example (jsfiddle).
I'm looking for some help on clearing the values of my input and text areas onclick after I insert an error message into the value of my inputs and textarea. Here's my code:
HTML
<form name="form" action="contact-handler.php" method="post" onsubmit="return contact();">
<input type="text" name="name" placeholder="Name:">
<input type="text" name="email" placeholder="E-mail:">
<select name="subject">
<option value="0">Categories</option>
<option value="1">Web Design</option>
<option value="2">Web Development</option>
<option value="3">Graphic Design</option>
<option value="4">Photography / Video</option>
<option value="5">Marketing</option>
</select>
<textarea name="message" placeholder="Message:"></textarea>
<input class="button" type="submit" value="Send">
</form>
JavaSript
function contact() {
var name = form.name.value;
var email = form.email.value;
var atPosition = email.indexOf("#");
var dotPosition = email.lastIndexOf(".");
var subject = form.subject.value;
var message = form.message.value;
var flag = 0;
// Name
if(name != "" && name.length > 2 && !/[\d]/.test(name)) {
flag++;
form.name.style.border="1px solid #CCC";
}
else{
form.name.style.border="1px solid #D73300";
form.name.value="Please enter a valid name";
}
// Email
if(email != "" && atPosition > 1 && dotPosition > atPosition + 2 && dotPosition + 2 <= email.length) {
flag++;
form.email.style.border="1px solid #CCC";
}
else{
form.email.style.border="1px solid #D73300";
form.email.value="Please enter a valid email";
}
// Subject
if(subject > 0) {
flag++;
form.subject.style.border="1px solid #CCC";
}
else{
form.subject.style.border="1px solid #D73300";
}
// Message
if(message != "" && message.length > 30) {
flag++;
form.message.style.border="1px solid #CCC";
}
else{
form.message.style.border="1px solid #D73300";
form.message.value="Please enter a valid message";
}
// Flag
if(flag == 4) {
return true;
}
else
{
return false;
}
}
Change the value of the placeholder attribute, not the input value. And use classes for styling:
form.element.className = 'error';
form.element.setAttribute('placeholder', "Can I haz a value?");
(fiddle)
A nicer way would be to add the required="required" attribute to your form elements, then you can just style them using the :invalid pseudo-class:
input:invalid, textarea:invalid{
border: ....
}
Vanilla JS way:
window.onload = function() {
var form = document.forms["form"];
var formElems = form.getElementsByTagName('input');
formElems.concat(form.getElementsByTagName('textarea'));
for(i=0; i<formElems.length; i++) {
formElems[i].onclick = function() {
if(this.style.borderColor == '#CCC') {
this.value = '';
}
}
}
};
put this above your contact function.