Модуль 6 · урок 8 з 12
Стани контролю
Найпоширеніша помилка у формах — показати помилку не тоді. Червоне «поле обовʼязкове» під порожнім полем, до якого користувач ще не дійшов, дратує сильніше, ніж відсутність валідації взагалі. Стани контролю саме про те, коли говорити.
Чотири пари станів
| Стан | Протилежний | Що означає |
|---|---|---|
touched | untouched | Користувач заходив у поле й вийшов із нього |
dirty | pristine | Значення змінювали |
valid | invalid | Валідатори пройдені |
enabled | disabled | Поле активне |
pending | Асинхронна перевірка триває | |
Ключова різниця, яку плутають: touched — про увагу, dirty —
про зміну. Можна зайти в поле й вийти, нічого не ввівши: воно стане
touched, але лишиться pristine.
Коли показувати помилку
// стандартна умова, до якої зводиться майже все
const showError = control.invalid && (control.touched || submitted);
Позначити все при відправці
save(): void {
if (this.form.invalid) {
this.form.markAllAsTouched(); // показати всі помилки одразу
this.focusFirstInvalid(); // і перевести фокус до першої
return;
}
this.api.create(this.form.getRawValue());
}
private focusFirstInvalid(): void {
const el = this.host.nativeElement.querySelector('.ng-invalid[formControlName]');
(el as HTMLElement | null)?.focus();
}
Перенесення фокуса — маленька деталь, яка сильно допомагає у довгих формах: користувач не мусить шукати очима, де саме проблема. У модулі 7 ми повернемось до цього як до вимоги доступності.
Класи, які Angular вішає сам
.ng-untouched .ng-touched
.ng-pristine .ng-dirty
.ng-valid .ng-invalid
.ng-pending
/* стилізувати можна прямо ними, без жодного коду в класі */
input.ng-invalid.ng-touched {
border-color: var(--color-danger);
}
input.ng-pending {
background-image: url('…'); /* індикатор перевірки */
}
Комбінація .ng-invalid.ng-touched — це рівно та сама умова показу помилки,
тільки на рівні CSS. Для рамки поля цього достатньо, і тоді в шаблоні лишається тільки
текст повідомлення.
Скидання форми
this.form.reset(); // значення й стани в початкові
this.form.reset({ status: 'todo' }); // зі значеннями за замовчуванням
this.form.markAsPristine(); // «вважати незміненою» без зміни значень
this.form.markAsUntouched();
Якщо форма лишається відкритою, після збереження виклич markAsPristine().
Інакше dirty залишиться true, і guard про незбережені зміни
з модуля 2 попередить про втрату даних, яких насправді вже немає. Це та деталь,
що звʼязує два модулі докупи.