Thinking about form validation, I just wanted something simple that works and is extensible.
I came up with the following code, which expects a list of selectors that maps to one or more functions performing validation. On success, a validator function returns a "falsey" value (empty string or false
, preferably) and on success, it returns the error text. The final result is a map from all inputs to one or more errors they produced.
Any comments on style and good practices, and also good use of ES-6 functionality, are welcome.
export default function validateForm(form, rules, baseSelector = 'input,textarea') {
let inputs = form.querySelectorAll(baseSelector);
let errorMap = new Map();
for (let input of inputs) {
errorMap.set(input, validateInput(input, rules));
}
return errorMap;
}
function validateInput(input, rules) {
let errors = [];
for (let rule of Object.keys(rules)) {
if (input.matches(rule)) {
let e = validateRule(input, rules[rule]);
errors.push(...e);
}
}
return errors;
}
function validateRule(input, validators) {
// In case only a single function is provided instead of an array
if (typeof validators === 'function') {
validators = [validators];
}
return validators
.map(validate => validate(input))
.filter(result => !!result);
}
Sample call:
function ensureRequired(input) {
if (!input.required || input.value) {
return '';
}
return 'required field not set';
}
function ensureNumber(input) {
if (Number.isInteger(input.value)) {
return '';
}
return 'field must be number';
}
let myForm = document.getElementById('myForm');
let validationResult = validateForm(myForm, {
'input': ensureRequired,
'input.phoneField': [ensureNumber]
};
Disclaimer: I'm aware HTML5 has built-in form validation - I was purposely trying to avoid using it.