Обработка ошибок валидации

Валидация в Angular — это механизм проверки корректности данных формы до их отправки или обработки. Ошибки валидации возникают на уровне элементов управления формой (FormControl), групп (FormGroup) или массивов (FormArray) и представляют собой структурированные данные, описывающие причину некорректного состояния.

Angular разделяет валидацию на:

  • Синхронную — выполняется сразу при изменении значения.
  • Асинхронную — требует обращения к серверу или выполнения отложенной логики.

Ошибки валидации хранятся в объекте errors, где ключ — имя валидатора, а значение — дополнительные данные об ошибке.


Ошибки валидации в Template-driven формах

В шаблонных формах валидация строится на директивах и HTML-атрибутах. Angular автоматически создаёт объект NgModel, который содержит состояние поля.

Пример поля с валидацией:

<input
  type="email"
  name="email"
  ngModel
  required
  email
  #emailModel="ngModel"
/>

Объект emailModel содержит:

  • valid / invalid
  • touched, dirty
  • errors

Структура errors может выглядеть так:

{
  required: true,
  email: true
}

Отображение ошибок

Ошибки проверяются через наличие ключей в errors:

<div *ngIf="emailModel.invalid && emailModel.touched">
  <div *ngIf="emailModel.errors?.required">
    Поле обязательно
  </div>
  <div *ngIf="emailModel.errors?.email">
    Некорректный email
  </div>
</div>

Ключевой момент — проверка touched или dirty, чтобы ошибки не отображались до взаимодействия с пользователем.


Ошибки валидации в Reactive Forms

В реактивных формах управление валидацией полностью переносится в TypeScript-код. Каждый FormControl хранит ошибки в свойстве errors.

Пример инициализации формы:

this.form = new FormGroup({
  username: new FormControl('', [
    Validators.required,
    Validators.minLength(4)
  ])
});

При некорректном вводе errors будет выглядеть так:

{
  required: true,
  minlength: {
    requiredLength: 4,
    actualLength: 2
  }
}

Проверка ошибок в шаблоне

<input formControlName="username" />

<div *ngIf="form.controls.username.invalid && form.controls.username.touched">
  <div *ngIf="form.controls.username.errors?.required">
    Имя пользователя обязательно
  </div>
  <div *ngIf="form.controls.username.errors?.minlength">
    Минимальная длина — 4 символа
  </div>
</div>

Встроенные валидаторы и их ошибки

Angular предоставляет стандартный набор валидаторов:

Валидатор Ключ ошибки Дополнительные данные
required required
minLength minlength requiredLength, actualLength
maxLength maxlength requiredLength, actualLength
email email
pattern pattern requiredPattern, actualValue

Понимание структуры ошибок позволяет формировать информативные сообщения без жёсткой привязки к тексту.


Пользовательские синхронные валидаторы

Пользовательский валидатор — это функция, возвращающая либо null, либо объект ошибок.

Пример:

function forbiddenNameValidator(control: AbstractControl) {
  return control.value === 'admin'
    ? { forbiddenName: true }
    : null;
}

Подключение:

new FormControl('', [forbiddenNameValidator]);

Объект errors:

{
  forbiddenName: true
}

Отображение:

<div *ngIf="control.errors?.forbiddenName">
  Это имя недопустимо
</div>

Пользовательские асинхронные валидаторы

Асинхронный валидатор возвращает Observable или Promise.

Пример:

function uniqueEmailValidator(service: UserService) {
  return (control: AbstractControl) => {
    return service.checkEmail(control.value).pipe(
      map(isTaken => (isTaken ? { emailTaken: true } : null))
    );
  };
}

Подключение:

new FormControl(
  '',
  [Validators.required],
  [uniqueEmailValidator(this.userService)]
);

Во время выполнения асинхронной валидации:

  • status = PENDING
  • ошибки отсутствуют до завершения проверки

Групповые ошибки валидации

Иногда проверка требует анализа нескольких полей одновременно. Валидация применяется к FormGroup.

Пример: проверка совпадения паролей.

function passwordMatchValidator(group: AbstractControl) {
  const password = group.get('password')?.value;
  const confirm = group.get('confirm')?.value;

  return password === confirm ? null : { passwordMismatch: true };
}

Подключение:

this.form = new FormGroup(
  {
    password: new FormControl(''),
    confirm: new FormControl('')
  },
  { validators: passwordMatchValidator }
);

Ошибка хранится в form.errors, а не в отдельных контролах.

Отображение:

<div *ngIf="form.errors?.passwordMismatch">
  Пароли не совпадают
</div>

Программная установка и очистка ошибок

Angular позволяет управлять ошибками вручную.

Установка:

control.setErrors({ serverError: 'Email уже существует' });

Очистка:

control.setErrors(null);

Частый сценарий — установка ошибок после ответа сервера при отправке формы.


Комбинирование серверных и клиентских ошибок

При серверной валидации рекомендуется:

  • использовать уникальные ключи (serverError, apiError)
  • не затирать существующие ошибки

Пример:

control.setErrors({
  ...control.errors,
  serverError: 'Ошибка сервера'
});

Так сохраняется информация о локальной валидации.


Унификация отображения ошибок

Для больших проектов характерна централизация обработки ошибок:

  • отдельный компонент для сообщений
  • pipe для преобразования ошибок в текст
  • словарь сообщений

Пример словаря:

const validationMessages = {
  required: 'Поле обязательно',
  minlength: (e) => `Минимум ${e.requiredLength} символа`,
  email: 'Некорректный формат'
};

Использование позволяет сократить шаблоны и обеспечить единый стиль сообщений.


Состояния контроля и их роль в обработке ошибок

Ключевые флаги:

  • touched — поле теряло фокус
  • dirty — значение изменено
  • pristine — значение не менялось
  • pending — выполняется асинхронная валидация

Грамотное сочетание этих состояний предотвращает преждевременное отображение ошибок и повышает качество пользовательского интерфейса.


Итоговая роль обработки ошибок валидации

Обработка ошибок валидации в Angular — это сочетание строгой структуры данных, гибких механизмов расширения и полного контроля со стороны разработчика. Корректная организация ошибок формирует предсказуемое поведение форм, облегчает сопровождение кода и позволяет масштабировать систему валидации без переписывания логики.