https://habrahabr.ru/post/346242/- Разработка веб-сайтов
- JavaScript
- Angular
Введение
Одним из достоинств Angular является широкий набор инструментов “из коробки”, которые позволяют быстро создавать формы любой сложности.
В Angular существует 2 подхода к созданию форм:
Template-driven forms — подход, в котором ключевую роль играет шаблон компонента, и все описание производится в нем — этот подход является развитием работы с формами в AngularJS;
Reactive forms — новый подход для работы с формами в реактивном стиле. Описание формы происходит в компоненте в виде дерева объектов, после чего это дерево связывается с шаблоном. Все манипуляции (проверка валидности, подписка на изменение значения и прочее) производятся в компоненте, что делает работу более гибкой, удобной и предсказуемой.
В данной статье мы разберем, как начать работать с
reactive forms на примере простой формы с валидацией и сообщениями об ошибках.
Код примера.
Создание реактивной формы
Подключим
ReactiveFormsModule в модуль, в котором будем использовать форму:
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { ReactiveFormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
@NgModule({
imports: [ BrowserModule, ReactiveFormsModule ],
declarations: [ AppComponent ],
bootstrap: [ AppComponent ]
})
export class AppModule { }
В реактивных формах используются 3 типа блоков:
Все они наследуются от
Abstract Control.
Описывать форму удобно, используя специальный инструмент
FormBuilder, с помощью которого можно создавать перечисленные выше блоки.
Добавим в компонент формы
FormBuilder и
FormGroup:
import { Component } from '@angular/core';
import { FormGroup, FormBuilder } from '@angular/forms';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent implements OnInit {
myFirstReactiveForm: FormGroup;
constructor(private fb: FormBuilder){}
ngOnInit(){}
}
Теперь опишем форму и
инициализируем ее в ngOnInit:
export class AppComponent implements OnInit {
myFirstReactiveForm: FormGroup;
constructor(private fb: FormBuilder){}
ngOnInit(){
this.initForm();
}
/** Инициализация формы*/
initForm(){
this.myFirstReactiveForm = this.fb.group({
name: ['Иван'],
email: [null]
});
}
}
Данная форма состоит из двух контролов:
- name со значением «Иван» при инициализации;
- email без стартового значения.
Свяжем форму с шаблоном компонента через директивы
formGroup и
formControlName:
<form [formGroup]="myFirstReactiveForm">
<label for="name">имя</label>
<input type="text" id="name" formControlName="name" />
<br/><br/>
<label for="email">email</label>
<input type="text" id="email" formControlName="email" />
<br/><br/>
<button type="submit">отправить</button>
</form>
Тут нужно обратить внимание на то, что formControlName принимает имя строкой и пишется без [ ].
Данные формы мы можем получить в компоненте в виде объекта через свойство
value и вывести их в шаблон через
jsonPipe (на данном этапе это необходимо для проверки работоспособности):
<div>
{{myFirstReactiveForm.value | json}}
</div>
Валидация и подсветка не валидных контролов
Angular предоставляет возможность валидации с помощью списка статических методов класса
Validators, проверяющих соответствие инпута определенным условиям.
Мы используем следующие:
- Validators.required — делает контрол обязательным для заполнения;
- Validators.email — валидация эл. адреса;
- Validators.pattern — валидация по регулярному выражению.
Импортируем валидаторы из
angular/forms в компонент:
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
Добавим их в описание контролов формы:
this.myFirstReactiveForm = this.fb.group({
name: ['', [
Validators.required,
Validators.pattern(/[А-я]/)
]
],
email: ['', [
Validators.required, Validators.email
]
]
});
На все контролы формы Angular динамически добавляет парные CSS классы в зависимости от определенных условий:
- ng-invalid/ng-valid — меняется в зависимости от валидности контрола;
- ng-pristine/ng-dirty — контрол считается dirty, если в нем хотя бы раз менялось значение;
- ng-untouched/ng-touched — контрол считается touched при первой потере фокуса.
В CSS добавим следующие стили:
input.ng-touched.ng-invalid{
border-color: red;
}
Теперь при введении неверных данных и потере фокуса контролы будут иметь красный бордер.Вывод сообщения об ошибке
Получить доступ к контролу в компоненте можно следующим образом:
this.myFirstReactiveForm.controls[controlName]
Проверим свойства
invalid и
touched.
Полный список свойств и методов контрола смотреть
здесь.
Добавим в компонент метод для проверки валидности контрола, который принимает на вход имя контрола и возвращает true/false:
isControlInvalid(controlName: string): boolean {
const control = this.myFirstReactiveForm.controls[controlName];
const result = control.invalid && control.touched;
return result;
}
В шаблоне добавим под контролом div с сообщением об ошибке, который будет отображаться по *ngIf, если контрол не валидный:
<label for="name">имя</label>
<input type="text" id="name" formControlName="name" />
<div class="error" *ngIf="isControlInvalid('name')">
Имя должно состоять только из русских букв
</div>
Для вывода разных ошибок (в зависимости от условий) можно воспользоваться библиотекой ngx-errors.Отправка формы
Добавим в компонент метод
onSubmit:
onSubmit() {
const controls = this.myFirstReactiveForm.controls;
/** Проверяем форму на валидность */
if (this.myFirstReactiveForm.invalid) {
/** Если форма не валидна, то помечаем все контролы как touched*/
Object.keys(controls)
.forEach(controlName => controls[controlName].markAsTouched());
/** Прерываем выполнение метода*/
return;
}
/** TODO: Обработка данных формы */
console.log(this.myFirstReactiveForm.value);
}
Если форма не валидна, через foreach помечаем все контролы как touched для подсветки ошибок и прерываем выполнение метода. В противном случае обрабатываем данные формы.
Добавим обработчик события
submit в шаблон:
<form [formGroup]="myFirstReactiveForm" (submit)="onSubmit()">
Форма готова!
Заключение
В следующей части разберем реактивную работу с формами, а именно:
подписку на событие изменения контрола;
динамический сброс и блокировку зависимых контролов;
динамическое добавление и удаление контролов и групп контролов в форму.
Ссылки
Код примера смотреть
здесь.
Более подробную информацию можно получить из
официальной документации.
Все интересующиеся Angular могут присоединяться к группе
русскоговорящего Angular сообщества в Telegram.