Validation
by reesewill
HTML
<form method="post" novalidate>
<p>
<label>Name:
<input type="text" name="name" data-rules="required">
</label>
<span class="error" aria-hidden="true" data-rule="required" data-for="name">This field is required</span>
</p>
<p>
<label>Email:
<input type="email" name="email" data-rules="required|email">
</label>
<span class="error" aria-hidden="true" data-rule="required" data-for="email">This field is required</span>
<span class="error" aria-hidden="true" data-rule="email" data-for="email">Enter a valid email address</span>
</p>
<p>
<label>Email: (Again)
<input type="email" name="email2" data-rules="required|email|isTheSame" data-same="email">
</label>
<span class="error" aria-hidden="true" data-rule="required" data-for="email2">This field is required</span>
<span class="error" aria-hidden="true" data-rule="email" data-for="email2">Enter a valid email address</span>
<span class="error" aria-hidden="true" data-rule="isTheSame" data-for="email2">Not the same as other input</span>
</p>
<p>
<label>Age:
<input type="number" name="age" data-rules="required">
</label>
<span class="error" aria-hidden="true" data-rule="required" data-for="age">This field is required</span>
</p>
<p>
<input type="submit" value="Submit">
</p>
</form>
SCSS
.error {
color: red;
display: block;
&[aria-hidden="true"] {
display: none;
}
}
JavaScript
function UndefinedRuleException(rule) {
this.message = "The specified rule '" + rule + "' doesn't exist."
}
function Rule(name, condition, test) {
this.name = name;
this.condition = condition;
this.test = test || ((value) => { return this.condition.test(value) });
}
// check that input is same as other input
function isTheSame(value, input) {
var sameName = input.getAttribute('data-same');
var sameInput = document.querySelector('[name="' + sameName + '"]');
var valid = true;
if (input.value && input.value != sameInput.value) {
valid = false;
}
return valid;
}
var rules = {};
rules.required = new Rule('required', /.+/);
rules.email = new Rule('email', /^(.+@.+)?$/);
rules.isTheSame = new Rule('isTheSame', null, isTheSame);
function Validator(input /*, rules...*/) {
this.input = input;
this.rules = [];
this.errorElements = {};
var rulesList = this.input.getAttribute('data-rules').split('|');
rulesList.forEach((rule) => {
if(rules[rule]) {
this.rules.push(rules[rule]);
this.errorElements[rule] = document.querySelector('.error[data-rule="' + rule + '"][data-for="' + this.input.name + '"]');
} else {
throw new UndefinedRuleException(rule);
}
});
this.input.addEventListener('blur', () => { this.test() });
}
Validator.prototype.test = function() {
var valid = true;
this.rules.forEach((rule) => {
var test = true;
if (!rule.test(this.input.value, this.input)) {
test = false;
valid = false;
}
this.errorElements[rule.name].setAttribute('aria-hidden', test);
});
return valid;
};
Validator.init = function() {
var validators = [];
document.querySelectorAll('[data-rules]').forEach(function(el) {
var validator = new Validator(el);
el.Validator = validator;
validators.push(validator);
});
document.querySelector('form').addEventListener('submit', (e) => {
var valid = true;
validators.forEach((validator) => {
if (!validator.test()) {
...