Проверка вводимых данных¶
28.02.2022
Вы можете улучшить общее качество данных, проверяя вводимые пользователем данные на точность и полноту. На этой странице показано, как проверять пользовательский ввод из пользовательского интерфейса и отображать полезные сообщения о проверке как в реактивных формах, так и в формах, управляемых шаблонами.
Предварительные условия¶
Прежде чем читать о валидации форм, вы должны иметь базовое представление о следующем.
- TypeScript и программирование на HTML5.
- Фундаментальные концепции дизайна приложений Angular
- два типа форм, которые поддерживает Angular
- Основы Template-driven Forms или Reactive Forms
Получите полный код примера для реактивных и управляемых шаблонами форм, используемых здесь для иллюстрации валидации формы. Запустите пример.
Валидация ввода в формах, управляемых шаблонами¶
Чтобы добавить валидацию в форму, управляемую шаблоном, вы добавляете те же атрибуты валидации, что и в встроенная валидация HTML-формы. Angular использует директивы для согласования этих атрибутов с функциями валидатора во фреймворке.
Каждый раз, когда значение элемента управления формы изменяется, Angular выполняет валидацию и генерирует либо список ошибок валидации, что приводит к статусу INVALID
, либо null
, что приводит к статусу VALID
.
Затем вы можете проверить состояние элемента управления, экспортировав ngModel
в локальную переменную шаблона. Следующий пример экспортирует NgModel
в переменную с именем name
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
|
Обратите внимание на следующие особенности, проиллюстрированные в примере.
-
Элемент
input
несет атрибуты проверки HTML:required
иminlength
.Он также содержит пользовательскую директиву валидатора,
forbiddenName
.Для получения дополнительной информации смотрите раздел Пользовательские валидаторы.
-
#name="ngModel"
экспортируетNgModel
в локальную переменнуюname
.NgModel
отражает многие свойства своего базового экземпляраFormControl
, поэтому вы можете использовать его в шаблоне для проверки состояний элемента управления, таких какvalid
иdirty
.Полный список свойств элементов управления приведен в справочнике API AbstractControl.
-
Функция
*ngIf
на элементеdiv
раскрывает набор вложенных сообщенийdiv
, но только еслиname
недействительно и элемент управления либоdirty
, либоtouched
. -
Каждый вложенный
div
может представлять пользовательское сообщение для одной из возможных ошибок валидации.Существуют сообщения для
required
,minlength
иforbiddenName
.
-
Чтобы валидатор не выводил ошибки до того, как у пользователя появится возможность редактировать форму, необходимо проверить наличие у элемента управления состояния dirty
или touched
.
-
Когда пользователь изменяет значение в наблюдаемом поле, элемент управления помечается как "грязный".
-
Когда пользователь размывает элемент управления формы, элемент управления помечается как "тронутый".
Проверка ввода в реактивных формах¶
В реактивной форме источником истины является класс компонента. Вместо того чтобы добавлять валидаторы через атрибуты в шаблоне, вы добавляете функции валидатора непосредственно в модель элемента управления формы в классе компонента.
Затем Angular вызывает эти функции при каждом изменении значения элемента управления.
Функции валидатора¶
Функции валидатора могут быть как синхронными, так и асинхронными.
Тип валидатора | Подробности |
---|---|
Синхронные валидаторы | Синхронные функции, которые принимают экземпляр элемента управления и немедленно возвращают либо набор ошибок валидации, либо null . Передайте их в качестве второго аргумента при инстанцировании FormControl . |
Асинхронные валидаторы | Асинхронные функции, которые принимают экземпляр элемента управления и возвращают Promise или Observable , которые позже выдают набор ошибок валидации или null . Передайте их в качестве третьего аргумента при инстанцировании FormControl . |
По соображениям производительности, Angular запускает асинхронные валидаторы только в том случае, если все синхронные валидаторы прошли. Каждый из них должен завершиться до появления ошибок.
Встроенные функции валидатора¶
Вы можете выбрать написать свои собственные функции валидатора или использовать некоторые встроенные валидаторы Angular.
Те же встроенные валидаторы, которые доступны как атрибуты в формах, управляемых шаблонами, такие как required
и minlength
, доступны для использования в качестве функций класса Validators
. Полный список встроенных валидаторов приведен в справочнике API Validators.
Чтобы обновить форму героя и сделать ее реактивной, используйте некоторые из тех же встроенных валидаторов — на этот раз в форме функции, как в следующем примере.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
В этом примере элемент управления name
устанавливает два встроенных валидатора — Validators.required
и Validators.minLength(4)
— и один пользовательский валидатор, forbiddenNameValidator
. (Подробнее смотрите пользовательские валидаторы.)
Все эти валидаторы являются синхронными, поэтому они передаются в качестве второго аргумента. Обратите внимание, что вы можете поддерживать несколько валидаторов, передавая функции в виде массива.
Этот пример также добавляет несколько методов getter. В реактивной форме вы всегда можете получить доступ к любому элементу управления формы через метод get
его родительской группы, но иногда полезно определить геттеры как сокращение шаблона.
Если вы снова посмотрите на шаблон для ввода name
, то он довольно похож на пример с шаблоном.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
Эта форма отличается от версии, основанной на шаблонах, тем, что она больше не экспортирует никаких директив. Вместо этого она использует геттер name
, определенный в классе компонента.
Обратите внимание, что атрибут required
все еще присутствует в шаблоне. Хотя он не нужен для валидации, его следует сохранить в целях доступности.
Определение пользовательских валидаторов¶
Встроенные валидаторы не всегда соответствуют конкретному случаю использования вашего приложения, поэтому иногда необходимо создать пользовательский валидатор.
Рассмотрим функцию forbiddenNameValidator
из предыдущих примеров reactive-form. Вот как выглядит определение этой функции.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Функция представляет собой фабрику, которая принимает регулярное выражение для определения конкретного запрещенного имени и возвращает функцию валидатора.
В данном примере запрещенным именем является "bob", поэтому валидатор отклоняет любое имя героя, содержащее "bob". В других местах он может отклонить "alice" или любое имя, которому соответствует конфигурирующее регулярное выражение.
Фабрика forbiddenNameValidator
возвращает настроенную функцию валидатора. Эта функция принимает объект управления Angular и возвращает либо null
, если значение элемента управления действительно, либо объект ошибки валидации.
Объект ошибки валидации обычно имеет свойство, имя которого — ключ валидации, 'forbiddenName'
, а значение — произвольный словарь значений, которые можно вставить в сообщение об ошибке, {name}
.
Пользовательские валидаторы async похожи на валидаторы sync, но вместо этого они должны возвращать Promise или наблюдаемую, которая позже выдает null
или объект ошибки валидации. В случае с наблюдаемой, она должна завершиться, после чего форма использует последнее выданное значение для валидации.
Добавление пользовательских валидаторов в реактивные формы¶
В реактивные формы можно добавить пользовательский валидатор, передав функцию непосредственно в FormControl
.
1 2 3 4 5 6 7 8 9 10 11 12 |
|
Добавление пользовательских валидаторов в формы, управляемые шаблонами¶
В формах, управляемых шаблонами, добавьте директиву в шаблон, где директива обертывает функцию валидатора. Например, соответствующая директива ForbiddenValidatorDirective
служит оберткой для forbiddenNameValidator
.
Angular распознает роль директивы в процессе валидации, поскольку директива регистрирует себя с провайдером NG_VALIDATORS
, как показано в следующем примере. NG_VALIDATORS
— это предопределенный провайдер с расширяемой коллекцией валидаторов.
1 2 3 4 5 6 7 |
|
Затем класс директивы реализует интерфейс Validator
, чтобы его можно было легко интегрировать с формами Angular. Ниже приведена остальная часть директивы, чтобы вы могли получить представление о том, как все это работает.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
|
Когда ForbiddenValidatorDirective
готова, вы можете добавить ее селектор, appForbiddenName
, к любому элементу ввода, чтобы активировать его. Например:
1 2 3 4 5 6 7 8 9 10 11 |
|
Обратите внимание, что пользовательская директива валидации инстанцируется с помощью useExisting
, а не useClass
. Зарегистрированный валидатор должен быть этим экземпляром директивы ForbiddenValidatorDirective
— экземпляром в форме с его свойством forbiddenName
, привязанным к "bob".
Если вы замените useExisting
на useClass
, то вы зарегистрируете новый экземпляр класса, у которого нет forbiddenName
.
CSS-классы состояния элемента управления¶
Angular автоматически отображает многие свойства элементов управления на элемент управления формы в виде классов CSS. Используйте эти классы для стилизации элементов управления формой в зависимости от состояния формы.
В настоящее время поддерживаются следующие классы.
.ng-valid
.ng-invalid
.ng-pending
.ng-pristine
.ng-dirty
.ng-untouched
.ng-touched
.ng-submitted
(заключающий элемент формы только)
В следующем примере форма героя использует классы .ng-valid
и .ng-invalid
для установки цвета границы каждого элемента формы.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
|
Валидация перекрестных полей¶
Межполевой валидатор — это пользовательский валидатор, который сравнивает значения различных полей в форме и принимает или отвергает их в комбинации. Например, у вас может быть форма, предлагающая взаимно несовместимые варианты, так что пользователь может выбрать A или B, но не оба.
Значения одних полей могут зависеть от других; пользователю может быть разрешено выбрать B только в том случае, если он также выбрал A.
Следующие примеры перекрестной валидации показывают, как сделать следующее:
- Валидировать реактивный или основанный на шаблоне ввод формы на основе значений двух родственных элементов управления,
- показать описательное сообщение об ошибке после того, как пользователь взаимодействовал с формой и проверка не прошла.
В примерах используется перекрестная валидация, чтобы убедиться, что герои не раскрывают свою истинную личность, заполняя форму героя. Валидаторы проверяют, что имена героев и их альтер-эго не совпадают.
Добавление перекрестной проверки в реактивные формы¶
Форма имеет следующую структуру:
1 2 3 4 5 |
|
Обратите внимание, что элементы управления name
и alterEgo
являются родственными элементами управления. Чтобы оценить оба элемента управления в одном пользовательском валидаторе, вы должны выполнить проверку в общем элементе управления-предке: FormGroup
. Вы запрашиваете FormGroup
для его дочерних элементов управления, чтобы сравнить их значения.
Чтобы добавить валидатор в FormGroup
, передайте новый валидатор в качестве второго аргумента при создании.
1 2 3 4 5 6 7 8 |
|
Код валидатора выглядит следующим образом.
1 2 3 4 5 6 7 8 9 10 11 |
|
Валидатор identity
реализует интерфейс ValidatorFn
. Он принимает в качестве аргумента объект элемента управления Angular и возвращает либо null, если форма валидна, либо ValidationErrors
в противном случае.
Валидатор получает дочерние элементы управления, вызывая метод FormGroup
get, затем сравнивает значения элементов управления name
и alterEgo
.
Если значения не совпадают, личность героя остается тайной, оба элемента являются действительными, и валидатор возвращает null. Если они совпадают, личность героя раскрывается, и валидатор должен пометить форму как недействительную, вернув объект ошибки.
Для улучшения пользовательского опыта шаблон показывает соответствующее сообщение об ошибке, если форма недействительна.
1 2 3 4 5 6 |
|
Этот *ngIf
выводит ошибку, если FormGroup
имеет ошибку кросс-валидации, возвращенную валидатором identityRevealed
, но только если пользователь закончил взаимодействие с формой.
Добавление перекрестной валидации в формы, управляемые шаблонами¶
Для формы, управляемой шаблоном, вы должны создать директиву для обертывания функции валидатора. Вы предоставляете эту директиву в качестве валидатора, используя токен NG_VALIDATORS
, как показано в следующем примере.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
Вы должны добавить новую директиву в HTML-шаблон. Поскольку валидатор должен быть зарегистрирован на самом высоком уровне в форме, следующий шаблон помещает директиву в тег form
.
1 |
|
Для повышения удобства пользователей при недействительности формы появляется соответствующее сообщение об ошибке.
1 2 3 4 5 6 |
|
Это одинаково как для форм, управляемых шаблонами, так и для реактивных форм.
Создание асинхронных валидаторов¶
Асинхронные валидаторы реализуют интерфейсы AsyncValidatorFn
и AsyncValidator
. Они очень похожи на свои синхронные аналоги, со следующими отличиями.
-
Функции
validate()
должны возвращать Promise или наблюдаемую, -
Возвращаемая наблюдаемая должна быть конечной, то есть она должна завершиться в какой-то момент.
Чтобы преобразовать бесконечную наблюдаемую в конечную, пропустите наблюдаемую через оператор фильтрации, такой как
first
,last
,take
илиtakeUntil
.
Асинхронная проверка происходит после синхронной проверки и выполняется только в случае успешной синхронной проверки. Эта проверка позволяет формам избежать потенциально дорогостоящих процессов асинхронной валидации (таких как HTTP запрос), если более простые методы валидации уже обнаружили недопустимый ввод.
После начала асинхронной проверки элемент управления формой переходит в состояние отложена
. Проверьте свойство pending
элемента управления и используйте его для визуальной обратной связи о текущей операции проверки.
Распространенным шаблоном пользовательского интерфейса является отображение спиннера во время выполнения асинхронной валидации. В следующем примере показано, как этого добиться в форме, управляемой шаблоном.
1 2 3 4 5 6 |
|
Реализация пользовательского асинхронного валидатора¶
В следующем примере асинхронный валидатор гарантирует, что герои выберут альтер-эго, которое еще не занято. Новые герои постоянно поступают на службу, а старые покидают ее, поэтому список доступных альтер-эго невозможно получить заранее.
Для проверки потенциального альтер-эго валидатор должен инициировать асинхронную операцию, чтобы обратиться к центральной базе данных всех ныне зачисленных героев.
Следующий код создает класс валидатора, UniqueAlterEgoValidator
, который реализует интерфейс AsyncValidator
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
Конструктор инжектирует HeroesService
, который определяет следующий интерфейс.
1 2 3 4 5 |
|
В реальном приложении HeroesService
будет отвечать за выполнение HTTP-запроса к базе данных героев, чтобы проверить, доступен ли альтер-эго. С точки зрения валидатора, фактическая реализация сервиса не важна, поэтому в примере можно просто написать код на основе интерфейса HeroesService
.
Когда начинается проверка, UniqueAlterEgoValidator
делегирует методу HeroesService
isAlterEgoTaken()
текущее значение элемента управления. В этот момент элемент управления помечается как pending
и остается в этом состоянии до тех пор, пока не завершится цепочка наблюдаемых, возвращенная из метода validate()
.
Метод isAlterEgoTaken()
отправляет HTTP-запрос, который проверяет, доступен ли альтер-эго, и возвращает Observable<boolean>
в качестве результата. Метод validate()
передает ответ через оператор map
и преобразует его в результат проверки.
Затем метод, как и любой другой валидатор, возвращает null
, если форма действительна, и ValidationErrors
, если нет. Этот валидатор обрабатывает любые потенциальные ошибки с помощью оператора catchError
.
В данном случае валидатор рассматривает ошибку isAlterEgoTaken()
как успешную валидацию, потому что неспособность выполнить запрос валидации не обязательно означает, что альтер-эго недействительно.
Вы можете обработать ошибку по-другому и вернуть вместо нее объект ValidationError
.
По истечении некоторого времени цепочка наблюдаемых завершается, и асинхронная валидация завершается. Флаг pending
устанавливается в false
, а валидность формы обновляется.
Добавление асинхронных валидаторов в реактивные формы¶
Чтобы использовать асинхронный валидатор в реактивных формах, начните с инъекции валидатора в конструктор класса компонента.
1 |
|
Затем передайте функцию валидатора непосредственно в FormControl
, чтобы применить ее.
В следующем примере функция validate
функции UniqueAlterEgoValidator
применяется к alterEgoControl
путем передачи ей опции asyncValidators
элемента управления и привязки ее к экземпляру UniqueAlterEgoValidator
, который был инжектирован в HeroFormReactiveComponent
. Значение asyncValidators
может быть либо одной функцией асинхронного валидатора, либо массивом функций.
Чтобы узнать больше об опциях FormControl
, смотрите API-справочник AbstractControlOptions.
1 2 3 4 5 6 7 8 |
|
Добавление асинхронных валидаторов в формы, управляемые шаблонами¶
Чтобы использовать асинхронный валидатор в формах, управляемых шаблонами, создайте новую директиву и зарегистрируйте на ней провайдер NG_ASYNC_VALIDATORS
.
В примере ниже директива инжектирует класс UniqueAlterEgoValidator
, содержащий логику валидации, и вызывает его в функции validate
, запускаемой Angular, когда валидация должна произойти.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
|
Затем, как и в случае с синхронными валидаторами, добавьте селектор директивы к входу, чтобы активировать ее.
1 2 3 4 5 6 7 8 9 |
|
Оптимизация производительности асинхронных валидаторов¶
По умолчанию все валидаторы запускаются после каждого изменения значения формы. В случае синхронных валидаторов это обычно не оказывает заметного влияния на производительность приложения.
Асинхронные валидаторы, однако, обычно выполняют какой-либо HTTP-запрос для проверки элемента управления.
Отправка HTTP-запроса после каждого нажатия клавиши может создать нагрузку на API бэкенда, и по возможности ее следует избегать.
Вы можете отложить обновление валидности формы, изменив свойство updateOn
с change
(default) на ubmit
или blur
.
Для форм, управляемых шаблонами, установите это свойство в шаблоне.
1 2 3 4 |
|
В реактивных формах установите свойство в экземпляре FormControl
.
1 |
|
Взаимодействие с собственной валидацией HTML-формы¶
По умолчанию Angular отключает родную валидацию HTML-формы, добавляя атрибут novalidate
на вложенную <form>
, и использует директивы для согласования этих атрибутов с функциями валидатора во фреймворке. Если вы хотите использовать родную валидацию в сочетании с валидацией на основе Angular, вы можете снова включить ее с помощью директивы ngNativeValidate
.
Подробности смотрите в API docs.