I am writing some logic to handle the behavior of input elements when a user focuses in on it, then clicks out of it and tries to submit without typing anything out in the input. An error should be the result. Now when the user focuses back into the input field, the error should remain until the uses starts typing something in the input, anything.
Now that is still a work in progress, but what I don't understand or what my expectation was, that I could write this logic out once and it would apply to all input elements, but it doesn't, it seems to just apply it to the first input element. Do I need to copy and paste the logic more than once per element?
I am already violating DRY principles all over the place. Why is this logic not applying to all input elements?
document.querySelector('input').addEventListener('blur', function (e) {
if (e.target.value.match(/^\s*$/)) {
document.querySelector('.animated-label').classList.add('error');
document.querySelector('.error-block').style.display = "block";
}
});
document.querySelector('input').addEventListener('focus', function (e) {
if (!e.target.value.match(/^\s*$/)) {
document.querySelector('.animated-label').classList.remove('error');
document.querySelector('.animated-label').classList.add('focus');
document.querySelector('.error-block').style.display = "none";
}
});
.rds-form .animated-label {
border: 2px solid #ccc;
border-radius: 2px;
color: #767676;
display: block;
min-height: 40px;
position: relative;
}
.rds-form .animated-label.focus {
border: 2px solid #8b0;
outline: thin dotted black;
outline-offset: 2px;
}
.rds-form .animated-label.required.field label:after {
background-color: #8b0;
border-radius: 50% 50%;
content: '';
display: inline-block;
height: 5px;
position: relative;
right: -0.5em;
top: -0.5em;
width: 5px;
}
.rds-form .field.animated-label.required.error label:after {
background-color: #cc2233;
}
.rds-form .field-group.error-group .error-block {
border-radius: 2px;
margin-bottom: 30px;
}
.rds-form .field-group.error-group .error-block .help-block {
padding-left: 40px;
position: relative;
}
<form class="rds-form">
<div class="row">
<div class="col-md-12">
<div class="field animated-label text required">
<label class="control-label" for="oldPassword">Current password</label>
<input class="form-control" type="password" id="oldPassword" aria-required="true" autocomplete="on" style="max-height: 67px; padding-top: 27px;" aria-invalid="true" aria-describedby="error-current-password">
<div class="error-block" style="display: none;">
<p class="help-block error" id="error-current-password">This is where the error should be.</p>
</div>
</div>
<div class="field animated-label text required">
<label class="control-label" for="NewPassword_NewPassword">New password</label>
<input class="form-control" type="password" name="NewPassword.NewPassword" id="NewPassword" aria-required="true" autocomplete="on" style="max-height: 67px; padding-top: 27px;" aria-invalid="true" aria-describedby="error-current-password">
<div class="error-block" style="display: none;">
<p class="help-block error" id="error-current-password">This is where the error should be.</p>
</div>
</div>
</div>
</div>
</form>
So the behavior you are seeing in the first input element, I want it to be the same behavior for all input elements in the form I create.
I tried iterating through the input
elements but I am not getting the functionality I was before:
const inputBlurs = document.querySelectorAll('input').addEventListener('blur', function (e) {
for (const i = 0, inputBlur; inputBlur = inputBlurs[i++];) {
if (e.target.value.match(/^\s*$/)) {
document.querySelectorAll('.animated-label').classList.add('error');
document.querySelectorAll('.error-block').style.display = "block";
}
}
});
const inputClicks = document.querySelectorAll('input').addEventListener('focus', function (e) {
for (const i = 0, inputClick; inputClick = inputClicks[i++];) {
if (!e.target.value.match(/^\s*$/)) {
document.querySelectorAll('.animated-label').classList.remove('error');
document.querySelectorAll('.animated-label').classList.add('focus');
document.querySelectorAll('.error-block').style.display = "none";
}
}
});
With the below implementation, I am still only getting one input element reacting to the focus and blur:
const errorHandler = e => {
const eTarg = e.target;
console.log(eTarg.tagName, e.type)
const inputs = document.querySelectorAll('input');
for (const i = 0; i < inputs.length; inputs++) {
if (eTarg.tagName === "INPUT" && eTarg.value.match(/^\s*$/)) {
if (e.type === "blur") {
document.querySelector('.animated-label').classList.add('error');
document.querySelector('.error-block').style.display = "block";
} else if (e.type==="focus") {
document.querySelector('.animated-label').classList.remove('error');
document.querySelector('.animated-label').classList.add('focus');
document.querySelector('.error-block').style.display = "none";
}
}
}
};
const transmit = e => alert(e.target)
document.querySelector('#myForm').addEventListener('focus', errorHandler, true); // NOTE the true
document.querySelector('#myForm').addEventListener('blur', errorHandler, true)