Модуль 6 · урок 4 з 12
Валідатори
Валідатор — це просто функція, яка дивиться на контрол і повертає обʼєкт помилки
або null. Уся система валідації Angular тримається на цій одній сигнатурі,
і саме тому свої правила писати легко.
Сигнатура
type ValidatorFn = (control: AbstractControl) => ValidationErrors | null;
// null означає «все добре» — це головна деталь, на якій плутаються
Вбудовані
Validators.required
Validators.requiredTrue // для чекбокса «згоден»
Validators.minLength(3)
Validators.maxLength(120)
Validators.min(0.5)
Validators.max(200)
Validators.pattern(/^[A-Z]{3,6}-\d+$/)
Validators.email
Свій валідатор
export function taskCode(): ValidatorFn {
return (control: AbstractControl): ValidationErrors | null => {
const value = String(control.value ?? '').trim();
if (!value) return null; // порожнє — не наша справа, це required
if (!/^[A-Z]{3,6}-\d{1,4}$/.test(value)) {
return { taskCode: { actual: value } }; // корисні дані для повідомлення
}
return null;
};
}
Не перевіряй порожнє значення у власному валідаторі. Для цього є
Validators.required. Інакше поле, яке взагалі не обовʼязкове, показуватиме
помилку формату, поки користувач до нього не дійшов. Один рядок
if (!value) return null; — і поведінка стає правильною.
Параметризований валідатор
export function maxWords(limit: number): ValidatorFn {
return (control) => {
const words = String(control.value ?? '').trim().split(/\s+/).filter(Boolean);
return words.length > limit
? { maxWords: { limit, actual: words.length } }
: null;
};
}
// у формі
title: ['', [Validators.required, maxWords(12)]],
Фабрика валідаторів — звичайне замикання: зовнішня функція приймає налаштування,
внутрішня має сигнатуру ValidatorFn. Це рівно те замикання з конспекту
до техдзвінка, тільки в ділі.
Валідатор на рівні групи
Коли правило стосується кількох полів одразу, вішати його на одне поле неправильно: воно не побачить сусідів. Такі валідатори ставлять на групу.
export function dateRange(fromKey: string, toKey: string): ValidatorFn {
return (group: AbstractControl): ValidationErrors | null => {
const from = group.get(fromKey)?.value;
const to = group.get(toKey)?.value;
if (!from || !to) return null;
return new Date(from) <= new Date(to)
? null
: { dateRange: true };
};
}
// у формі — другим аргументом групи
this.fb.nonNullable.group(
{
startDate: [''],
dueDate: [''],
},
{ validators: [dateRange('startDate', 'dueDate')] },
);
@if (form.errors?.['dateRange']) {
<p class="field__error">Дата завершення не може бути раніше за початок</p>
}
Помилка групового валідатора лежить у form.errors, а не в
form.controls.dueDate.errors. Це часта плутанина: людина шукає помилку в полі,
не знаходить і вирішує, що валідатор не працює. Показувати таку помилку теж треба окремо —
зазвичай під усією групою полів.
Керування валідаторами
control.setValidators([Validators.required]); // замінити всі
control.addValidators(maxWords(12)); // додати
control.removeValidators(Validators.required);
control.clearValidators();
control.updateValueAndValidity(); // ⚠️ обовʼязково після зміни — інакше нічого не станеться