Модуль 6 · урок 2 з 12
Будівельні блоки
Реактивна форма складається з трьох цеглин, які вкладаються одна в одну. Зрозумівши їх, ти зможеш описати форму будь-якої складності — від двох полів до дерева з динамічними секціями.
FormControl — одне поле
const title = new FormControl('', {
nonNullable: true, // про це наступний урок
validators: [Validators.required, Validators.maxLength(120)],
});
title.value; // поточне значення
title.setValue('Нова назва');
title.patchValue('…'); // для контролу те саме, різниця буде в групі
title.reset(); // повернути до початкового
title.valid; // пройшов валідацію
title.errors; // { required: true } або null
title.touched; // користувач заходив і виходив із поля
title.dirty; // значення міняли
title.disable(); // вимкнути — і виключити зі значення форми
title.enable();
FormGroup — обʼєкт із полів
const form = new FormGroup({
code: new FormControl('', { nonNullable: true }),
title: new FormControl('', { nonNullable: true }),
estimate: new FormControl(1, { nonNullable: true }),
});
form.value; // { code, title, estimate } — але без вимкнених полів
form.getRawValue(); // усі поля, включно з вимкненими
form.controls.code; // доступ до контролу — типізований
form.patchValue({ title: 'Нова' }); // оновити частину полів
form.setValue({ … }); // оновити ВСІ поля — інакше помилка
value чи getRawValue — важлива пастка
form.value не містить вимкнених полів. Тобто якщо поле
code заблоковане при редагуванні, у value його просто не буде —
і на бекенд поїде обʼєкт без коду. Правило просте: для відправки на сервер завжди
getRawValue().
FormArray — список однотипних
const form = new FormGroup({
title: new FormControl('', { nonNullable: true }),
subtasks: new FormArray<FormControl<string>>([]),
});
// додати
form.controls.subtasks.push(new FormControl('', { nonNullable: true }));
// видалити
form.controls.subtasks.removeAt(2);
// перебрати в шаблоні
form.controls.subtasks.controls; // масив контролів
FormBuilder — щоб не писати new
private readonly fb = inject(FormBuilder);
protected readonly form = this.fb.nonNullable.group({
code: ['', [Validators.required, Validators.pattern(/^[A-Z]{3,6}-\d+$/)]],
title: ['', [Validators.required, Validators.maxLength(120)]],
estimate: [1, [Validators.min(0.5), Validators.max(200)]],
assigneeId: this.fb.control<string | null>(null),
subtasks: this.fb.array<FormControl<string>>([]),
});
fb.nonNullable — саме те, що потрібно: усі контроли створюються
з nonNullable: true, і не доводиться писати це в кожному рядку. Наступний урок
пояснить, чому це принципово.
Прив'язка в шаблоні
<form [formGroup]="form" (ngSubmit)="save()">
<label for="code">Код</label>
<input id="code" formControlName="code">
<div formGroupName="meta"> <!-- вкладена група -->
<input formControlName="tag">
</div>
<div formArrayName="subtasks">
@for (ctrl of form.controls.subtasks.controls; track $index) {
<input [formControlName]="$index">
}
</div>
<button type="submit" [disabled]="form.invalid">Зберегти</button>
</form>