Вступление
Одна из наиболее распространенных функций любого веб-приложения - это предоставление пользователям формы для ввода некоторых данных. Вы используете формы ежедневно для входа в систему, регистрации, размещения заказов и т. Д.
Обработка вводимых пользователем данных перед проверкой может иметь серьезные последствия. Вы можете в конечном итоге сохранить неверные данные, такие как неправильная дата, адрес электронной почты, возраст и т. Д. Это также может быть проблемой безопасности из-за таких атак, как межсайтовый скриптинг (XSS).
Традиционный способ проверки HTML-форм - использование JavaScript или JQuery. К сожалению, этот подход требует большого количества кода.
Angular , будучи полноценным фреймворком, обеспечивает отличную поддержку для проверки вводимых пользователем данных и отображения сообщений проверки. Он имеет множество обычно используемых встроенных валидаторов, которыми вы можете воспользоваться, или даже можете написать свои собственные валидаторы.
Формы в Angular
Форма Angular - это обычная HTML-форма с несколькими дополнительными
функциями. Для каждого поля (input, radio, select и т. Д.) В форме нам
понадобится объект класса FormControl
Объект FormControl
предоставляет информацию об этом поле. Его value
, если значение
valid
, а если оно недействительно, каковы errors
проверки и т. Д.
Он также показывает состояние поля, такое как touched
, untouched
,
dirty
, pristine
и т. Д.
Точно так же FormGroup
- это коллекция объектов FormControl
Каждая
форма Angular имеет как минимум одну FormGroup
. Вы можете решить
использовать несколько FormGroup
в таких случаях использования, как
разделение разделов обработки личных и профессиональных данных в форме
регистрации пользователя.
Все свойства FormGroup
( valid
, error
и т. Д.) Также доступны для
FormControl
. Например, valid
свойство FormControl
вернет true
если все FormControl
действительны.
Итак, чтобы добавить валидацию в форму Angular, нам нужны две вещи:
- По крайней мере, один
FormGroup
для формы - Объект
FormControl
для каждого поля в форме
Есть два разных способа создания этих управляющих объектов. Мы можем предоставить некоторые директивы в шаблоне формы, и Angular может создать такие элементы управления для нас. Формы, созданные таким образом, называются формами на основе шаблонов .
Если у нас есть какие-то особые варианты использования и нам нужен больший контроль над формой, мы можем явно создавать такие объекты управления . Формы, созданные таким образом, называются реактивными формами .
Формы на основе шаблонов
В формах на основе шаблонов мы применяем ngModel
для каждого поля в
шаблоне. Angular создает FormControl
под капотом для каждого такого
поля и связывает его с соответствующим полем:
<div class="form-group">
<label for="name">Name</label>
<input type="text" class="form-control" id="name"
ngModel name="name">
</div>
<div class="form-group">
<label for="username">Username</label>
<input type="text" class="form-control" id="username"
ngModel name="username">
</div>
Примечание . Для ngModel
требуется либо FormControl
name
либо
определить FormControl как «автономный» в ngModelOptions
, иначе
Angular выдаст ошибку.
Кроме того, в app.module.ts
вам нужно будет добавить FormsModule
в
массив импорта:
import { FormsModule } from '@angular/forms';
// ...some other imports
imports: [
//...some other imports
FormsModule
]
Проверка в формах на основе шаблонов
Angular предоставил несколько встроенных валидаторов для проверки
распространенных вариантов использования. Чтобы использовать встроенные
валидаторы, вам нужно будет применить атрибуты валидации к каждому полю
формы, где вы хотите валидацию. Эти атрибуты проверки такие же, как
обычные атрибуты проверки HTML5, такие как required
, minlength
,
maxlength
и т. Д. В рамках hod Angular предоставил директивы для
сопоставления этих атрибутов с функциями проверки, определенными в
структуре Angular.
Каждый раз, когда значение FormControl
изменяется, Angular генерирует
список ошибок проверки, выполняя проверку. Если список пуст, это
означает, что это действительный статус, в противном случае это
недопустимый статус.
Допустим, мы хотим ввести в него следующие проверки:
- Поскольку поля Name и Username имеют
required
атрибут, мы хотим отобразить сообщение проверки, если это поле оставлено пустым. - Поле имени должно иметь значение,
minlegth
иmaxlength
должны составлять 2 и 30 символов соответственно. - Если в имени пользователя есть пробелы, отобразить сообщение о недопустимом имени пользователя.
ngModel
управления формой, в который мы хотим добавить проверку, нам
нужно добавить соответствующие атрибуты проверки и экспортировать
ngModel в локальную переменную шаблона :
<input type="text" class="form-control" id="name"
required maxlength="30" minlength="2"
ngModel name="name" #name="ngModel">
В приведенном выше примере мы использовали следующие встроенные
валидаторы - required
, minlength
и maxlength
.
Мы можем использовать name
переменной шаблона в шаблоне для проверки
состояний валидации используемых валидаторов:
<div *ngIf="name.invalid && (name.dirty || name.touched)"
class="alert alert-danger">
<div *ngIf="name.errors.required">
Name is required.
</div>
<div *ngIf="name.errors.minlength">
Name cannot be more than 30 characters long.
</div>
<div *ngIf="name.errors.minlength">
Name must be at least 2 characters long.
</div>
</div>
Поскольку мы использовали условный оператор для рендеринга первого div
, он будет отображаться только в том случае, если статус встроенного
валидатора invalid
. В начале раздела мы объяснили, как статус
определяется как valid
или invalid
.
Точно так же внутренний div's
будет отображаться только в том случае,
если name
переменной шаблона имеет свойство errors
а errors
имеет
одно из следующих свойств - required
, minlength
и maxlength
и
значение свойства id true
. Мы уже обсуждали, как переменная шаблона
привязывается к ngModel
и она получает эти свойства каждый раз, когда
происходит какое-либо изменение в элементе управления формы и после
того, как Angular запускает проверку для этого поля.
Примечание . Важно проверять состояние « dirty
и « touched
, в
противном случае сообщение об ошибке будет отображаться при первой
загрузке страницы, что плохо для пользователя. Нам нужно, чтобы
сообщение проверки отображалось в одном из следующих условий:
- Пользователь меняет какое-то значение, т.е. поле грязное (
formControlObject.dirty
) - Пользователь использует табуляцию или щелчки для переключения фокуса
на какой-либо другой элемент, т.е. к полю было прикосновение (
formControlObject.touched
)
Если вы хотите сослаться на полный список встроенных валидаторов Angular, вы можете воспользоваться API валидаторов .
Написание собственного валидатора
Иногда встроенные валидаторы могут не соответствовать вашему конкретному варианту использования. В этом случае вам может потребоваться создать собственную функцию валидатора.
Функция валидатора реализует ValidatorFn
, что означает, что у него
должна быть подпись:
interface ValidatorFn {
(control: AbstractControl): ValidationErrors | null
}
ValidationErrors
должен быть объектом, имеющим одну или несколько пар
ключ-значение:
type ValidationErrors = {
[key: string]: any;
};
Ключ должен быть строкой и используется для обозначения типа ошибки
проверки, например, invalidEmail
, required
и т. Д. Значение может
быть любым и используется для предоставления дополнительной информации
об ошибке проверки.
В приведенном выше примере мы хотим написать настраиваемую функцию проверки, которая проверяет, нет ли пробелов в имени пользователя .
Хотя технически мы можем написать эту функцию в любом месте приложения, всегда рекомендуется помещать все связанные функции валидатора в отдельный класс:
import { ValidationErrors, AbstractControl } from '@angular/forms';
export class UserRegistrationFormValidators {
static usernameShouldBeValid(control: AbstractControl): ValidationErrors | null {
if ((control.value as string).indexOf(' ') >= 0) {
return { shouldNotHaveSpaces: true }
}
// If there is no validation failure, return null
return null;
}
}
Примечание . В этом примере мы вернули true
в качестве значения
ключа shouldNotHaveSpaces
потому что нам не нужно предоставлять
какие-либо подробности. В некоторых случаях вам может потребоваться
предоставить подробную информацию, например:
return { maxlengthExceeded: {
maxLength: 20,
actual: control.value.length
}
}
Затем мы можем использовать эту функцию валидатора
UserRegistrationFormValidators.usernameShouldBeValid
для username
в
нашей форме, управляемой шаблоном:
<div class="form-group">
<label for="username">Username</label>
<input type="text" class="form-control" id="username"
required
UserRegistrationFormValidators.usernameShouldBeValid
[(ngModel)]="person.username" name="username">
</div>
Реактивные формы
В реактивных формах мы создаем FormControl
явно в компоненте этого
шаблона. Вот обычная HTML-форма без каких-либо директив или ngModel
<div class="form-group">
<label for="name">Name</label>
<input type="text" class="form-control" id="name">
</div>
<div class="form-group">
<label for="username">Username</label>
<input type="text" class="form-control" id="username">
</div>
Предположим, мы хотим преобразовать нашу управляемую шаблоном форму из предыдущего примера в реактивную форму.
Для этого, во-первых, нам нужно явно создать FormGroup
и
FormControls
для каждого поля в компоненте шаблона:
form = new FormGroup({
'name': new FormControl(),
'username': new FormControl(),
})
Примечание : Как обсуждалось ранее, форма может иметь более одной
FormGroup
. В этом случае у нас может быть вложенная структура:
registrationForm = new FormGroup({
'personalDetailsForm': new FormGroup({
'name': new FormControl()
})
})
Вы можете узнать больше о FormGroup
в документации
Angular .
Позвольте мне снова обратить ваше внимание на наш вариант использования.
Затем нам нужно связать эти FormControl
с полями в форме HTML.
<form [formGroup]="registrationForm">
<div class="form-group">
<label for="name">Name</label>
<input type="text" class="form-control" id="name"
[formControlName]="name">
</div>
<div class="form-group">
<label for="username">Username</label>
<input type="text" class="form-control" id="username"
[formControlName]="username">
</div>
<form>
Здесь мы применили formGroup
и связали ее с объектом FormGroup
registrationForm
который мы создали в компоненте . Мы также
связывали formControlName
директиву с соответствующим FormControl
объектами name
и username
.
Примечание . Директивы для создания реактивных форм определены в
ReactiveFormsModule
. Итак, если вы получите такую ошибку, как:
Can't bind to formGroup
... тогда вы должны проверить, импортировали ли вы этот
ReactiveFormsModule
в свой основной модуль app.module.ts
.
Валидации в реактивных формах
В реактивных формах мы не ngModel
а также не используем атрибуты
проверки HTML5. Мы указываем валидаторы при создании объектов
FormControl
в самом компоненте.
Вот подпись класса FormControl
class FormControl extends AbstractControl {
constructor(formState: any = null, validatorOrOpts?: ValidatorFn | AbstractControlOptions | ValidatorFn[], asyncValidator?: AsyncValidatorFn | AsyncValidatorFn[])
// ...
}
Как мы видим, первый параметр - это начальное состояние элемента
управления, которое можно оставить пустым, т.е. ''
. Второй параметр -
ValidatorFn
.
Чтобы добавить встроенные функции валидатора для FormControl
мы можем
передать ему соответствующий ValidatorFn
. В следующем примере мы
использовали следующие встроенные валидаторы required
, minLength
и
maxLength
-:
registrationForm = new FormGroup({
'name': new FormControl('Enter your name', [
Validators.required,
Validators.minLength(2),
Validators.maxLength(30)
]),
'username': new FormControl('', Validators.required),
})
Примечание . Вам потребуется импортировать Validators
в компонент.
Также обратите внимание, что в отличие от форм на основе шаблонов, мы не
используем атрибуты проверки . Мы используем соответствующие
ValidatorFn
такие как Validators.required
, Validators.minLength (2)
и т. Д. Ваш редактор кода может обеспечивать автозаполнение для всех
ValidatorFn
тот момент, когда вы вводите Validators
с точкой .
.
Мы можем вернуться к шаблону и написать сообщения проверки:
<form [formGroup]="registrationForm">
<div class="form-group">
<label for="name">Name</label>
<input type="text" class="form-control" id="name"
[formControlName]="name">
<div *ngIf="registrationForm.get('name').invalid && (registrationForm.get('name').dirty || registrationForm.get('name').touched)"
class="alert alert-danger">
<div *ngIf="registrationForm.get('name').errors.required">
Name is required.
</div>
<div *ngIf="registrationForm.get('name').errors.minlength">
Name cannot be more than 30 characters long.
</div>
<div *ngIf="registrationForm.get('name').errors.minlength">
Name must be at least 2 characters long.
</div>
</div>
</div>
<div class="form-group">
<label for="username">Username</label>
<input type="text" class="form-control" id="username"
[formControlName]="username">
</div>
<form>
Пользовательские валидаторы для реактивных форм
Нам нужно написать настраиваемую функцию валидатора так же, как мы это
сделали для раздела формы, управляемой шаблоном. Мы можем использовать
ту же настраиваемую функцию валидатора
UserRegistrationFormValidators.usernameShouldBeValid
в компоненте для
реактивной формы :
registrationForm = new FormGroup({
'name': new FormControl('Enter your name', [
Validators.required,
Validators.minLength(2),
Validators.maxLength(30)
]),
'username': new FormControl('', [
Validators.required,
UserRegistrationFormValidators.usernameShouldBeValid
]),
})
Заключение
В этом руководстве мы изучили два разных способа обработки пользовательского ввода - формы на основе шаблонов и реактивные формы. Мы узнали, как проверять оба типа форм. И, наконец, мы также написали нашу пользовательскую функцию валидатора и включили ее во встроенные валидаторы.
Как мы видим, Angular имеет отличную поддержку форм и предоставляет некоторые внутренние полезные функции для проверки форм. Предоставление каждой функции с помощью форм Angular выходит за рамки этого руководства. Вы можете прочитать документацию по Angular для получения полной информации.