Angular IDPStrong Junior
Модулі / Форми / Валідатори
🔥 0

Модуль 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();   // ⚠️ обовʼязково після зміни — інакше нічого не станеться