JavaScript: Проверка формы с Constraint Validation API

Проверка формы — одна из основных причин использования клиентского JavaScript. Это может предотвратить ошибки ввода пользователя до того, как выше приложение попытается отправить данные на сервер.

Проверка на стороне клиента не заменяет проверку на стороне сервера!

Всегда проверяйте входящие пользовательские данные на сервере. Не каждый запрос будет исходить от браузера, и не каждый браузер будет запускать код проверки. Проверка на стороне клиента — это усовершенствование, которое делает вашу систему более удобной в использовании.

Тем не менее вам может не потребоваться JavaScript для более простой проверки формы…

Проверка поля HTML5

Современные браузеры, поддерживающие HTML5, могут проверять поля без JavaScript. Атрибут type устанавливает ограничения и может изменять пользовательский интерфейс стандартного поля <input>:

ТипОписание
buttonкнопка без поведения по умолчанию
checkboxфлажок или переключатель
colorвыбор цвета
dateвыбор даты для года, месяца и дня
datetime-localвыбор даты и времени
emailввод email
fileвыбор файла
hiddenскрытое поле
imageкнопка, которая отображает изображение заданное в src атрибуте
monthвыбор месяца и года
numberввод номера
passwordввод пароля (скрытый текст)
radioрадио кнопка
rangeползунок
resetсбрасывает все поля формы до значений по умолчанию
searchполе поиска
submitкнопка отправки формы
telтелефонный номер
textтекстовый ввод
timeвыбор времени (без временной зоны)
urlввод URL
weekвыбор номера недели и года

Если вы не указываете или используете неподдерживаемый атрибут, браузер назначает полю тип text. Это должно позволить пользователю вводит данные в старых браузерах, даже если это не может быть проверено автоматически.

Другие атрибуты управления ограничениями включают:

АтрибутОписание
acceptтип загружаемого файла
altатрибут alt для изображения
autocompleteподсказка автодополнения
autofocusполе фокуса
captureметод захвата мультимедиа
checkedотмеченный checkbox или radio
disabledотключённое поле — оно не проверяется и не отправляется
formсвязать с формой, используя указанный id
formactionURL для отправки (submit и button)
inputmodeподсказка типа данных (none, text, tel, url, email, numeric, decimal, search)
listid &lt;datalist&gt;
maxмаксимальное значение
maxlengthмаксимальная длинна строки
minминимальное значение
minlengthминимальная длинна строки
nameимя элемента управления (отправляется на сервер)
patternрегулярное выражение шаблона проверки поля, напр. [1-3]+ одна и больше цифр от 1 до 3
placeholderтекст-заполнитель для пустого поля
readonlyПоле не может редактироваться - оно проверяется и отправляется
requiredобязательное поле
sizeразмер элемента управления, обычно переопределяется в CSS
spellcheckустанавливается true или false для проверки орфографии
srcURL изображения
stepшаг увеличения значения в number и/или range
valueначальное значение

Интерфейс input

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

Используйте самый очевидный тип type, но будьте осторожны с особыми случаями, такими как кредитные карты. Это числовые значения, но ролик мыши и курсорные клавиши бесполезны. Лучше использовать стандартный ввод text:

<input
type="text"
name="ccnumber"
inputmode="numeric"
autocomplete="cc-number"
/>

Браузер может предлагать такие функции, как съёмка камерой или подтверждение по SMS, когда встречает тип autocomplete.

Встроенная проверка/валидация

Браузер гарантирует, что значение соответствует ограничениям атрибутов type, min, max, step, minlength, maxlength, pattern, и required:

<input type="number" min="1" max="100" required />

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

  1. атрибут novalidate в <form>, или
  2. атрибут formnovalidate в кнопку отправки формы

CSS стили проверки/валидации

Следующие псевдоклассы позволяют стилизовать input в соответствии с его состоянием:

СелекторОписание
:focusПоле на котором фокус
:focus-withinэлемент содержащий полое с фокусом
:focus-visibleэлемент на который переведён фокус с помощью клавиатуры
:requiredполе с атрибутом required
:optionalполе без атрибута required
:validполе прошедшее проверку
:invalidполе не прошедшее валидацию
:user-validполе прошедшее валидацию после взаимодействия с пользователем (только Firefox)
:user-invalidполе не прошедшее валидацию после взаимодействия с пользователем (только Firefox)
:in-rangeзначение находится в пределах допустимого диапазона
:out-of-rangeзначение выходит за пределы допустимого диапазона
:disabledполе с атрибутом disabled
:enabledполе без атрибута disabled
:read-onlyполе с атрибутом read-only
:read-writeполе без атрибута read-only
:checkedотмеченный checkbox или radio button
:indeterminateнеопределённое состояние checkbox или radio button
:defaultэлементы установленные по умолчанию

Эти селекторы имеют одинаковую специфичность, поэтому порядок не важен. Например:

input:invalid { color: red; }
input:enabled { color: blue; }

Поля input с недопустимыми значениями окрашиваются в красный, но это переопределяется, потому что все не отключённые поля выделены синим цветом.

Вы должны быть осторожны, потому что браузер применяет стили валидации при загрузке страницы. В следующем примере каждое поле считается не прошедшим валидацию и содержит текст красного цвета и обведено красной рамкой ещё до того, как пользователь взаимодействовал с формой:

:invalid {
color: red;
border-color: red;
}

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

Constrain Validation API

Constraint Validation API предоставляет параметры настройки, которые могут улучшить или изменить стандартное поведение проверки полей HTML5. Вы можете выполнять проверку после взаимодействия с пользователем, отображать определённые сообщения об ошибках или реализовать программную проверку, например подтвердить:

1. Отключение проверки формы по умолчанию

Ваш код должен отключать валидацию формы по умолчанию и сообщения об ошибках, установив свойство атрибута <form> noValidate = true, например:

const myform = document.getElementById('myform');
myform.noValidate = true;

2. Добавление обработчика событий формы

Далее, вы должны добавить обработчик событий для отправки формы или изменения отдельных полей, например:

// валидация формы при отправке
myform.addEventListener('submit', validateForm);

Функция обработчик может проверить, что вся форма валидна используя методы элемента формы:

  1. checkValidity() — возвращает true, если все дочерние элементы соответствуют ограничениям и проходят валидацию.
  2. reportValidity() — возвращает true, если дочерний элемент не подлежит валидации или соответствует ограничениям.

Обратите внимание, что оба метода вызывают событие invalid event для каждого не валидного поля. Оно не всплывает, поэтому обработчики должны быть установлены по мере необходимости для каждого поля.

Эта простая функция обработчик останавливает отправку формы, когда одно или несколько полей не проходят валидацию:

// Валидация формы при отправке
function validateForm(e) {

const form = e.target;

if (!form.checkValidity()) {

// Форма не прошла валидацию - отменить отправку
e.preventDefault();
e.stopImmediatePropagation();

}

};

3. Валидация отдельных полей

Отдельные поля имеют следующие свойства и методы проверки ограничений:

ValidityStateОписание
.badInputбраузер не может распознать введённые данные
.customErrorбыло установлено пользовательское сообщение о валидации
.patternMismatchзначение не соответствует указанному шаблону атрибута
.rangeOverflowзначение больше атрибута max
.rangeUnderflowзначение меньше атрибута min
.stepMismatchзначение не соответствует правилу атрибута step
.tooLongдлинна строки больше значения атрибута maxlength
.tooShortдлинна строки меньше значения атрибута minlength
.typeMismatchзначение не соответствует валидному email или URL
.valueMissingтребуемое значение пустое

Функция-обработчик validateForm() может пройтись по всем полям формы и применить класс invalid к его родительскому элементу.

function validateForm(e) {

const
form = e.target,
field = Array.from(form.elements);

// применяем/удаляем класс invalid
field.forEach(i => {
if (i.checkValidity()) {
// поле валидно - удаляем класс
i.parentElement.classList.remove('invalid');
}
else {
// поле не валидно -- добавляем класс
i.parentElement.classList.add('invalid');
}
});

if (!form.checkValidity()) {
// форма не прошла валидацию - отменяем отправку
e.preventDefault();
e.stopImmediatePropagation();
}
};

Если вы определили обязательное поле email в вашей html5 форме:

<div>
<label for="email">email</label>
<input type="email" id="email" name="email" required />
<p class="help">Please enter a valid email address.</p>
</div>

Этот скрипт добавит класс invalid к контейнеру <div>, когда значение поля email не проходит валидацию. CSS может изменить стиль и показать или скрыть сообщение об ошибке:

.help { display: none; }

.invalid .help { display: block; }

.invalid label, .invalid input, .invalid .help {
color: red;
border-color: red;
}

4. Добавление проверки пользовательского поля

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

Функция validateForm():

// проверка формы
function validateForm(e) {

const
form = e.target,
field = Array.from(form.elements);

// сброс полей
field.forEach(i => {
i.setCustomValidity('');
i.parentElement.classList.remove('invalid');
});

// email или телефон заданы?
const err = form.email.value || form.tel.value ? '' : 'error';
form.email.setCustomValidity(err);
form.tel.setCustomValidity(err);

if (!form.checkValidity()) {

// форма не прошла валидацию - отмена отправки
e.preventDefault();
e.stopImmediatePropagation();

// добавляем класс invalid
field.forEach(i => {
if (!i.checkValidity()) {
// поле не прошло валидацию - добавляем класс
i.parentElement.classList.add('invalid');
}
});
}
}

Резюме

Валидация формы может быть обыденной, но это необходимая деятельность веб-разработчика. Время написания собственных регулярных выражения для электронной почты и проверки введённых чисел давно прошло. Используйте стандартные типы input, а затем, при необходимости проверяйте их с Constraint Validation API.

Никогда не забывайте проверять пользовательские данные на сервере!

Дополнительные материалы

Предыдущая Статья

Возможности ES2022: блоки статической инициализации класса

Следующая Статья

Зачем нужны веб-фреймворки и как обойтись без них