Валидация ограничений
Создание веб-форм всегда было сложной задачей. Хотя сверстать саму форму достаточно просто, проверить, имеет ли каждое поле валидное значение — сложнее, а информирование пользователя о проблеме может стать настоящей головной болью. HTML5 представил для форм новый механизм: он добавляет элементу <input>
новые семантические типы и constraint validation, чтобы облегчить проверку содержимого на стороне клиента. С помощью новых атрибутов основные ограничения могут быть проверены без использования JavaScript; более сложные ограничения могут быть проверены с помощью Constraint validation API.
Базовое введение в эти концепции с примерами можно найти в разделе Валидация форм на стороне клиента.
Примечание: HTML5-валидация ограничений не отменяет необходимости дополнительной валидации на стороне сервера. Несмотря на то, что ожидается гораздо меньшее не валидных запросов формы, они всё же могут быть отправлены несовместимыми браузерами (например, не поддерживающими HTML5 или JavaScript) или злоумышленниками, которые пытаются взломать ваше веб-приложение. Следовательно, как и в случае с HTML4, вам по-прежнему нужно производить дополнительную валидацию ограничений ввода и на стороне сервера.
Внутренние и базовые ограничения
В HTML5 базовые ограничения объявляются двумя способами:
- Задавать семантически наиболее подходящие значения для атрибута
type
элемента<input>
. Например, типаemail
автоматически создаёт ограничение, которое проверяет, является ли значение валидным email-адресом. - Использовать атрибуты валидации, позволяющие достаточно просто задать ограничения без помощи JavaScript.
Семантические типы input
Внутренние ограничения атрибута type
:
Тип input | Описание ограничения | Связанное нарушение |
---|---|---|
<input type="URL"> |
Значение должно быть URL-адресом, как указано в URL Living Standard. | Нарушение ограничения TypeMismatch |
<input type="email"> |
Значение должно быть синтаксически правильным email-адресом, который обычно имеет формат username@hostname.tld . |
Нарушение ограничения TypeMismatch |
Для обоих этих типов input, если установлен атрибут multiple
допускается ввод нескольких разделённых запятыми значений. Если какое-то из значений не удовлетворяет условию, описанному выше, срабатывает нарушение ограничения Type mismatch.
Обратите внимание, что большинство типов input не имеют внутренних ограничений, так как некоторые из них недоступны для валидации ограничений или имеют алгоритм, по умолчанию преобразующий неправильные значения в правильные.
Атрибуты валидации
В дополнение к атрибуту type
, описанному выше, для описания основных ограничений используются следующие атрибуты:
Атрибут | Типы input, поддерживающие атрибут | Возможные значения | Описание ограничения | Связанное нарушение |
---|---|---|---|---|
pattern
|
text , search , url ,
tel , email , password
|
Регулярное выражение JavaScript
(без
ECMAScript 5
флагов global , ignoreCase , and
multiline
|
Значение должно соответствовать шаблону. |
Нарушение ограничения
patternMismatch
|
min
|
range , number |
Валидное число | Значение в поле должно быть больше или равно значению атрибута |
Нарушение ограничения
rangeUnderflow
|
date , month , week |
Валидная дата | |||
datetime , datetime-local , time
|
Валидная дата и время | |||
max
|
range , number |
Валидное число | Значение в поле должно быть меньше или равно значению атрибута |
Нарушение ограничения
rangeOverflow
|
date , month , week |
Валидная дата | |||
datetime , datetime-local , time
|
Валидная дата и время | |||
required
|
text , search , url ,
tel , email , password ,
date , datetime , datetime-local ,
month , week , time ,
number , checkbox , radio ,
file ; а также элементы <select>
и <textarea>
|
Нет, так как это булев атрибут: его наличие означает true, а отсутствие — false | В поле обязательно должно быть значение (если установлен атрибут) |
valueMissing
constraint violation
|
step
|
date |
Целое число дней |
Если для шага не задан литерал any , значением должно быть
min + целое число, кратное шагу
|
Нарушение ограничения
stepMismatch
|
month |
Целое число месяцев | |||
week |
Целое число недель | |||
datetime , datetime-local , time
|
Целое число секунд | |||
range , number |
Целое число | |||
minlength
|
text , search , url ,
tel , email , password ; а также
элемент <textarea> /td>
|
Целое число |
Если атрибут не пустой, количество символов (точек кода) содержимого
поля не должно быть меньше значения, указанного в атрибуте. Все символы
новой строки нормализованы до одного символа (в отличие от CRLF-пар) для
<textarea> .
|
Нарушение ограничения
tooShort
|
maxlength
|
text , search , url ,
tel , email , password ; а также
элемент <textarea>
|
Целое число | Количество символов (точек кода) содержимого поля не должно превышать значение, указанное в атрибуте |
Нарушение ограничения
tooLong
|
Процесс валидации ограничений
Валидация ограничений выполняется с помощью Constraint Validation API либо на отдельном элементе формы, либо на уровне формы, на самом элементе <form>
. Способы валидации:
- Вызов метода
checkValidity()
илиreportValidity()
связанного с формой DOM-интерфейса, (HTMLInputElement
,HTMLSelectElement
,HTMLButtonElement
,HTMLOutputElement
илиHTMLTextAreaElement
), который оценивает ограничения только на данном элементе, позволяя скрипту получить эту информацию. МетодcheckValidity()
возвращает логическое значение, указывающее, соотвествует ли значение элемента его ограничениям. (Обычно это делает браузер при определении того, какой CSS-псевдоклассов применяется::valid
или:invalid
.) Напротив, методreportValidity()
сообщает пользователю о любых нарушениях ограничений. - Вызов метода
checkValidity()
илиreportValidity()
интерфейсаHTMLFormElement
. - Отправка самой формы.
Вызов метода checkValidity()
называется статической валидацией ограничений, а вызов метода reportValidity()
или отправка формы называется интерактивной валидацией ограничений.
Примечание:- Если элементу <form>
задан атрибут novalidate
, интерактивная валидация ограничений не произойдёт.
- Вызов метода
submit()
интерфейсаHTMLFormElement
не запускает валидацию ограничений. Другими словами, этот метод отправляет данные формы на сервер, даже если ограничения нарушены. Вместо него вызовите методclick()
кнопки отправки формы.
Сложные ограничения с помощью Constraint Validation API
С помощью JavaScript и Constraint Validation API можно реализовать более сложные ограничения, например, ограничения, касающиеся сразу нескольких полей или ограничения, включающие сложные вычисления.
По сути, идея заключается в том, чтобы при наступлении определённого события поля формы (например, onchange) запускать JavaScript, чтобы определить, нарушено ограничение, и затем с помощью метода field.setCustomValidity()
, задать результат валидации: пустая строка означает, что ограничение соблюдается, а любая другая строка означает, что есть ошибка и эта строка является сообщением об ошибке, которое нужно показать пользователю.
Ограничение, объединяющее несколько полей: Валидация почтового индекса
Формат почтового индекса в разных странах отличается. Мало того, что в большинстве стран может быть дополнительный префикс с кодом страны (например, D —
в Германии, F —
во Франции или Швейцарии), в некоторых странах, почтовые индексы содержат фиксированное количеством цифр; другие, например, Великобритания, имеют ещё более сложную структуру, допускающую в определённых местах ещё и наличие букв.
Примечание: Далее представлена не полная библиотека валидации почтового индекса, а скорее демонстрация ключевых концепций.
В качестве примера мы добавим скрипт, выполняющий валидацию органичений простой формы:
<form>
<label for="ZIP">ZIP : </label>
<input type="text" id="ZIP" />
<label for="Country">Country : </label>
<select id="Country">
<option value="ch">Switzerland</option>
<option value="fr">France</option>
<option value="de">Germany</option>
<option value="nl">The Netherlands</option>
</select>
<input type="submit" value="Validate" />
</form>
Получим следующую форму:
Сначала запишем функцию, проверяющую само ограничение:
function checkZIP() {
// Для каждой страны определяем шаблон, которому должен следовать почтовый индекс
var constraints = {
ch: [
"^(CH-)?\\d{4}$",
"Switzerland ZIPs must have exactly 4 digits: e.g. CH-1950 or 1950",
],
fr: [
"^(F-)?\\d{5}$",
"France ZIPs must have exactly 5 digits: e.g. F-75012 or 75012",
],
de: [
"^(D-)?\\d{5}$",
"Germany ZIPs must have exactly 5 digits: e.g. D-12345 or 12345",
],
nl: [
"^(NL-)?\\d{4}\\s*([A-RT-Z][A-Z]|S[BCE-RT-Z])$",
"Nederland ZIPs must have exactly 4 digits, followed by 2 letters except SA, SD and SS",
],
};
// Прочитать id страны
var country = document.getElementById("Country").value;
// Получить поле NPA
var ZIPField = document.getElementById("ZIP");
// Создать валидатор ограничения
var constraint = new RegExp(constraints[country][0], "");
console.log(constraint);
// Валидировать индекс
if (constraint.test(ZIPField.value)) {
// Индекс соответствует ограничению, мы используем ConstraintAPI, чтобы сообщить об этом
ZIPField.setCustomValidity("");
} else {
// Индекс не соответствует ограничению , мы используем ConstraintAPI, чтобы
// показать сообщение, описывающее формат, требуемый для данной страны
ZIPField.setCustomValidity(constraints[country][1]);
}
}
Затем мы связываем его с событием onchange для <select>
и с событием oninput для <input>
:
window.onload = function () {
document.getElementById("Country").onchange = checkZIP;
document.getElementById("ZIP").oninput = checkZIP;
};
Ограничение размера загружаемого файла
Ещё одним распространённым ограничением является лимит размера загружаемых файлов. Данная проверка на стороне клиента перед отправкой на сервер требует сочетания Constraint Validation API и особенно метода field.setCustomValidity()
с другим JavaScript API, в данном случае — File API.
Вот часть HTML:
<label for="FS">Select a file smaller than 75 kB : </label>
<input type="file" id="FS" />
Она отображает:
JavaScript считывает выбранный файл, с помощью метода File.size()
получает его размер, сравнивает его с лимитом и вызывает Constraint Validation API, чтобы сообщить браузеру о нарушении:
function checkFileSize() {
var FS = document.getElementById("FS");
var files = FS.files;
// Если выбран хотя бы один файл
if (files.length > 0) {
if (files[0].size > 75 * 1024) {
// Проверить ограничение
FS.setCustomValidity("Размер файла не должен превышать 75 kB");
return;
}
}
// Если нарушения ограничений нет
FS.setCustomValidity("");
}
Наконец мы связываем метод с нужным событием:
window.onload = function () {
document.getElementById("FS").onchange = checkFileSize;
};
Визуальное оформление нарушения ограничений
Помимо установки ограничений, веб-разработчики хотят управлять тем, какие сообщения показываются пользователям и как они оформлены.
Управление внешним видом элементов
Изменять внешний вид элементов можно с помощью CSS-псевдоклассов.
CSS-псевдоклассы :required и :optional
Псевдоклассы :required
и :optional
позволяют писать селекторы, соответствующие элементам формы, которые имеют или не имеют атрибут required
CSS-псевдокласс :placeholder-shown
Смотрите :placeholder-shown
CSS-псевдоклассы :valid и :invalid
Псевдоклассы :valid
и :invalid
используются для представления элементов <input>, содержимое которых является валидным или не валидным соответственно. Эти классы позволяют пользователю оформлять валидные или не валидные элементы формы, чтобы облегчить определение элементов, которые имеют корректный или некорректный формат.
Управление текстом нарушения ограничений
Следующее может помочь с управлением текстом нарушения ограничений:
-
Метод element.setCustomValidity(message) для элементов:
<fieldset>
. Примечание: Добавление кастомного сообщения валидации на элемент fieldset не предотвращает отправку формы в большинстве браузеров.<input>
<output>
<select>
- Кнопка отправки формы в виде элемента
<button>
илиinput
submit
с указанным типом submit. Другие типы кнопок не участвуют в валидации ограничений. <textarea>
-
Интерфейс
ValidityState
описывает объект, возвращаемый свойством validity перечисленных выше типов элементов. Он представляет разные способы определения не валидности значения. Вместе они помогают объяснить, почему значение элемента не проходит валидацию, если оно не валидно.