Реактивные формы и валидация
Реактивная форма — это модель формы в коде: структура, значения и правила валидации описаны в классе, а не разбросаны по HTML.
«Шаблонные формы — это форма, нарисованная в HTML. Реактивные — форма, спроектированная в коде, где ей и место в серьёзном приложении».
Формы — кровь бизнес-приложений: регистрация, оформление заказа, фильтры. Angular даёт два подхода, и для сложных случаев предпочтительны реактивные формы: вся структура и правила живут в TypeScript, что делает их предсказуемыми и тестируемыми. Строится форма из FormControl (одно поле) и FormGroup (группа полей):
import { Component, inject } from '@angular/core';
import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';
@Component({
selector: 'app-signup',
standalone: true,
imports: [ReactiveFormsModule],
template: `
<form [formGroup]="form" (ngSubmit)="submit()">
<input formControlName="email" placeholder="Email" />
@if (form.controls.email.invalid && form.controls.email.touched) {
<small>Введите корректный email</small>
}
<input formControlName="password" type="password" />
<button [disabled]="form.invalid">Регистрация</button>
</form>
`,
})
export class SignupComponent {
private fb = inject(FormBuilder);
form = this.fb.group({
email: ['', [Validators.required, Validators.email]],
password: ['', [Validators.required, Validators.minLength(8)]],
});
submit() {
if (this.form.valid) console.log(this.form.value);
}
}
Директива [formGroup] связывает форму с разметкой, formControlName привязывает каждое поле. Валидаторы (required, email, minLength) задают правила, а форма сама отслеживает состояние: valid, invalid, touched, dirty.
Как работает под капотом
Каждый FormControl — это объект с текущим значением и статусом. При вводе он прогоняет значение через цепочку валидаторов; каждый возвращает либо null (всё хорошо), либо объект ошибки. Статус группы выводится из статусов полей: группа невалидна, если невалидно хоть одно поле. Флаг touched ставится, когда пользователь покинул поле, — это позволяет показывать ошибку не сразу, а после взаимодействия.
ввод в поле email
|
FormControl прогоняет валидаторы:
required -> null (ок)
email -> { email: true } (ошибка!)
|
статус поля = INVALID
|
FormGroup: есть невалидное поле -> вся форма INVALID
|
[disabled]="form.invalid" -> кнопка заблокирована
Запускаемая врезка: валидация формы на JS
Соберём мини-движок валидации. «Попробуй сам ▶».
// валидаторы: возвращают null (ок) или текст ошибки
const required = v => (v ? null : 'обязательно');
const email = v => (/.+@.+\..+/.test(v) ? null : 'неверный email');
const minLen = n => v => (v.length >= n ? null : 'минимум ' + n);
function validate(value, validators) {
return validators.map(fn => fn(value)).filter(Boolean); // только ошибки
}
console.log(validate('', [required, email]));
// ["обязательно", "неверный email"]
console.log(validate('[email protected]', [required, email]));
// [] (валидно)
console.log(validate('123', [minLen(8)]));
// ["минимум 8"]
Частые ошибки
- Забыть импортировать
ReactiveFormsModule— директивы формы не заработают. - Показывать ошибку всегда. Проверяйте
touched, чтобы не пугать пользователя до ввода. - Несовпадение
formControlNameи ключа в группе. Имена должны быть идентичны.
Best practices
- Для нетривиальных форм выбирайте реактивный подход — он тестируем и масштабируется.
- Блокируйте кнопку отправки при
form.invalid. - Показывайте ошибки по условию
invalid && touched.
Итоги. Реактивные формы описывают структуру и правила в коде через FormGroup/FormControl и валидаторы, автоматически отслеживая статус. Это надёжный выбор для серьёзных форм. Дальше — общение с сервером через HTTP.
Закрепляем
Реактивные формы переносят структуру и правила формы из HTML в TypeScript-код, и в этом их сила. Форма собирается из FormControl (одно поле) и FormGroup (группа полей), а правила задаются валидаторами вроде required, email и minLength. Поскольку вся модель формы живёт в коде, её легко читать, переиспользовать и покрывать тестами — поэтому для нетривиальных форм реактивный подход предпочтительнее шаблонного.
Форма сама ведёт богатый учёт своего состояния, и грамотный вывод ошибок опирается на эти флаги. valid и invalid говорят о соответствии правилам; touched ставится, когда пользователь покинул поле; dirty — когда значение менялось. Показывайте сообщение об ошибке по условию invalid && touched, чтобы не пугать человека красным текстом ещё до того, как он начал вводить данные. И блокируйте кнопку отправки при form.invalid — это простой способ не дать отправить заведомо некорректные данные. Не забудьте импортировать ReactiveFormsModule, иначе директивы формы не оживут.
| Элемент | Назначение |
|---|---|
| FormControl | Одно поле формы |
| FormGroup | Группа полей |
| Validators | Правила проверки |
| valid / touched | Состояние для вывода ошибок |