Все статьи

HTML5 валидация

October 26, 2017

С появлением 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);
  • позволяет отправить форму.

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

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

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

  • 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. Прошу рассматривать эту библиотеку как учебный материал и заготовку для реальных задач. Здесь могут быть не учтены все моменты.

Итого

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