HTML5 валидация

С появлением HTML5, урааа, появились нативные средства валидации. С помощью html атрибутов можно указать, как проверять то или иное поле, большинство разработчиков их знает и использует. Например:

  • required - поле станет обязательным для заполнения;
  • minlength - нельзя будет ввести значения, меньше заданной длины;
  • pattern - задает регулярное выражение для проверки значения поля.

с полным списком можно ознакомиться здесь https://www.w3schools.com/html/html_form_attributes.asp

А с помощью псевдоклассов :valid и :invalid, в css можно подсветить корректное / некорректное поле. Также в атрибуте title поля формы для проверки паттерном можно поменять текст предупреждения.

Вроде бы это должно помочь с клиентской проверкой форм, прощайте костыли и плагины, но работает это иногда странно.. Например, minlength вообще не поддерживается IE и EDGE (ох уж эти майкрософт). А пустое поле с атрибутом required не помешает сделать сабмит формы в сафари.

Но самое главное, системные сообщения всегда выглядят по-разному

IE/EDGE:

Firefox:

Google Chrome:

В итоге нет кастомизации. Как видим эти сообщения могут перекрыть наши сообщения или другие элементы, также могут не устроить клиента, могут не сочетаться с дизайном. И казалось бы все, нет повсеместного применения нативной валидации, но…

Constraint Validation API

Суть в том, что каждое поле нативно хранит состояние валидности по совершенно разным параметрам, и это все отслеживается в JS без подключения сторонних библиотек, и этот API работает везде, разве с небольшими недочетами в IE и EDGE.

Как его использовать?

Изначально придется кое-чем пожертвовать, и разрешить отправить неправильную форму для отключения системных сообщений с помощью атрибута формы novalidate.

novalidate:

  • отключает системные сообщения;
  • сохраняет состояния валидности (JS, CSS);
  • позволяет отправить форму.
<form novalidate action="#" class="form__block">

Саму логику валидации предлагаю обернуть в маленькую функцию-библиотеку.

Создание библиотеки

Наша функция на вход будет принимать три параметра:

  • formSelector - формы, которые будем валидировать;
  • setError - функция, которая будет выделять поле с ошибкой;
  • deleteError - функция, которая будет выделять поле, заполненное успешно.
const validation = function({ formSelector, setError, deleteError }) {};

1) Отключим системные уведомления об ошибках для выбранных форм, и найдем в них поля.

const forms = document.querySelectorAll(formSelector);
const fields = [];
for (let i = 0; i < forms.length; i++) {
forms[i].addEventListener('invalid', event => {
    event.preventDefault();
}, true);
const inputs = forms[i].querySelectorAll('input');
for (let j = 0; j < inputs.length; j++) {
    fields.push(inputs[j])
  }
}

2) Создадим массив атрибутов, по которым будем валидировать поля

const validations = [
'typeMismatch',
'tooShort',
'tooLong',
'valueMissing',
'badInput',
'rangeOverflow',
'rangeUnderflow',
'patternMismatch'
];

Кратко о атрибутах валидации:

  • badInput - указывает, есть ли данные, которые браузер вообще не может преобразовать (нет поддержки IE11);
  • patternMismatch - указывает, соответствуют ли данные паттерну, заданным в атрибуте pattern;
  • rangeOverflow - указывает, превышает ли значение максимальное, заданное в атрибуте max;
  • rangeUnderflow - указывает, превышает ли значение минимальное, заданное в атрибуте min;
  • stepMismatch - указывает, соответствует ли значение правилам, определенным атрибутом step (то есть не равномерно делится на значение шага);
  • tooLong - указывает, превышает ли длина значение максимальное, заданное в атрибуте maxlength;
  • tooShort - указывает, превышает ли длина значение минимальное, заданное в атрибуте minlength (Не работает в IE/EDGE, проверку можно сделать через паттерн);
  • typeMismatch - указывает, соответствует ли значение типу, заданному в атрибуте type;
  • valueMissing - указывает, не пустое ли значение, работает с помощью required;
  • valid - указывает, что поле валидно учитывая все ограничения.

https://developer.mozilla.org/ru/docs/Web/API/ValidityState - здесь оригинал

3) Создадим функцию, которая будет проверять поле по каждому атрибуту валидности

const setValidate = field => {
let isValid = true;
validations.forEach(validator => {
    if (field.validity[validator]) {
        setError(field);
        isValid = false;
    }
});
if (isValid) {
    deleteError(field);
}
return isValid;
};

То есть здесь в цикле по каждому состоянию в отдельности проверяем поле, и для каждого состояния можем сделать необходимую манипуляцию. Например несоответствие типу обработать одним образом, а пустоту другим. Такие действия можно совершать, например, при снятии фокуса и перед submit.

4) Вызов проверки валидации

В данном случае, предлагаю валидировать поля при расфокусировке

for (let i = 0; i < fields.length; i++) {
const field = fields[i];
field.addEventListener('blur', setValidate.bind(null, field));
}

5) Проверка всей формы

Так как мы отключили проверку всей формы, мы должны обработать проверку при сабмите.

А саму функцию проверки формы вернем нашей библиотекой

const formValidate = form => {
const currentInputs = form.querySelectorAll('input');
let isValid = true;
for (let i = 0; i < currentInputs.length; i++) {
    const field = currentInputs[i];
    isValid = setValidate(field)
}
return isValid;
};

Завершение

Могли заметить, что мы использовали, современный стандарты JS - ES6+, который не поддерживается в IE. Для решения этого момента и для того, чтобы библиотека меньше весила, прогоним ее через webpack+babel.

Результат

https://github.com/perryutkonos/validator/ - библиотека с примером

https://github.com/perryutkonos/validator/tree/master/src/index.js - исходник библиотеки

https://github.com/perryutkonos/validator/tree/master/dist - готовая библиотека

https://github.com/perryutkonos/validator/tree/master/example - пример интеграции

https://perryutkonos.github.io/validator/example/ - демо примера


P.S. Прошу рассматривать эту библиотеку как учебный материал и заготовку для реальных задач. Здесь могут быть не учтены все моменты.

Итого

Мы можем, используя только стандартные атрибуты, только с проверкой состояния (без считывания значений из формы, проверки их на регулярку, пустоту и прочего в скрипте), сделать очень гибкую кастомизируемую валидацию.


По любым вопросам жду в телеграме @NikitinRoman


Автор:
Никитин Роман
Разработчик Digital Spectr