Проверка пользовательских форм в Angular
В этой статье я расскажу, как создать кастомизатор из валидатора для приложений Angular и добавить этот валидатор в управляемые шаблоном формы или в реактивные формы.
Здесь я собираюсь продемонстрировать проверку поля ввода номера телефона, которое должно состоять из 10 цифр.
Вот два скриншота, которые иллюстрируют, как наша валидация будет выглядеть как пользовательский интерфейс:
Валидатор для шаблонной формы
Для проверки в формах на основе шаблонов используются директивы, поэтому давайте продолжим и создадим директиву phone-number-validator
.
import { Directive } from '@angular/core';
import { Validator, AbstractControl, NG_VALIDATORS } from '@angular/forms';
@Directive({
selector: '[phoneValidateDirective]',
providers: [{
provide: NG_VALIDATORS,
useExisting: AppPhoneValidateDirective,
multi: true
}]
})
export class AppPhoneValidateDirective implements Validator {
validate(control: AbstractControl) : {[key: string]: any} | null {
if (control.value && control.value.length != 10) {
return { 'phoneNumberInvalid': true }; // return object if the validation is not passed.
}
return null; // return null if validation is passed.
}
}
Не забудьте зарегистрировать и добавить валидатор в существующий массив валидаторов, предоставляемый Angular NG_VALIDATORS
:
// ...
providers: [{
provide: NG_VALIDATORS,
useExisting: Your_Class_Name,
multi: true
}]
// ...
Здесь я создал директиву валидации телефонного номера, которая реализует интерфейс Validator
из @angular/forms
, для которого мы должны предоставить следующий метод реализации: validate(control: AbstractControl): : {[key: string]: any} | null
. Этот валидатор вернет объект, если валидация не пройдена, { 'phoneNumberInvalid': true }
и null
, если валидация пройдена.
Angular добавляет возвращаемое значение функции проверки в свойстве errors
. Если свойство errors
не пусто, то форма недействительна.
Phone number must be of 10 digit
Валидатор для реактивных форм
Для проверки в Reactive Forms мы должны создать функцию.
import { FormBuilder, AbstractControl } from '@angular/forms';
import { Component, OnInit } from "@angular/core";
@Component({
selector: 'reactive-form',
templateUrl: './reactive-form.component.html'
})
export class AppReactiveForm implements OnInit {
myForm: FormGroup;
constructor(
private fb: FormBuilder
) {}
ngOnInit() {
this.myForm = this.fb.group({
phone: ['', [ValidatePhone]] // added the function in validators array of form-control
});
}
}
function ValidatePhone(control: AbstractControl): {[key: string]: any} | null {
if (control.value && control.value.length != 10) {
return { 'phoneNumberInvalid': true };
}
return null;
}
Мы добавляем функцию в массив валидаторов FormControl.
Объединение обоих валидаторов
Мы можем объединить оба валидатора, чтобы не повторять наш код и следовать принципам DRY (не повторять себя):
import { Directive } from '@angular/core';
import { Validator, AbstractControl, NG_VALIDATORS } from '@angular/forms';
export function ValidatePhone(control: AbstractControl): {[key: string]: any} | null {
if (control.value && control.value.length != 10) {
return { 'phoneNumberInvalid': true };
}
return null;
}
@Directive({
selector: '[phone]',
providers: [{
provide: NG_VALIDATORS,
useExisting: AppPhoneValidateDirective,
multi: true
}]
})
export class AppPhoneValidateDirective implements Validator {
validate(control: AbstractControl) : {[key: string]: any} | null {
return ValidatePhone(control);
}
}