JavaRush /Курсы /Модуль 4: Node.js, Next.js и Angular /Встроенные валидаторы: Va...

Встроенные валидаторы: Validators.required, email, minLength

Модуль 4: Node.js, Next.js и Angular
16 уровень , 7 лекция
Открыта

1. Введение

Представьте себе интернет-магазин, где можно оформить заказ, указав e-mail "котик", а телефон — "много восьмерок и пару смайликов". Как думаете, как быстро владельцы магазина начнут искать нового программиста? Валидация — это тот самый невидимый "охранник", который не пропустит в систему неправильные данные.

Angular даёт нам мощный инструментарий для валидации форм. Сегодня мы рассмотрим три самых популярных (и полезных!) валидатора:

  • Validators.required — поле обязательно для заполнения.
  • Validators.email — поле должно содержать валидный email.
  • Validators.minLength — минимальная длина строки.

Давайте разберёмся, как они работают и как их подключать на практике.

Как добавить валидаторы к полям формы?

Всё очень просто: валидаторы подключаются прямо при создании FormControl. Можно передать их в конструктор вторым аргументом, а если их несколько — использовать массив.

Пример: минимальная форма с валидаторами

import { Component } from '@angular/core';
import { FormGroup, FormControl, Validators } from '@angular/forms';

@Component({
  selector: 'app-register-form',
  template: `
    <form [formGroup]="registerForm">
      <input formControlName="email" placeholder="Email">
      <input formControlName="password" placeholder="Пароль" type="password">
      <button>Зарегистрироваться</button>
    </form>
  `
})
export class RegisterFormComponent {
  registerForm = new FormGroup({
    email: new FormControl('', [Validators.required, Validators.email]),
    password: new FormControl('', [Validators.required, Validators.minLength(6)])
  });
}

Что здесь происходит:
— Для поля email мы требуем обязательное заполнение (Validators.required) и корректный формат email (Validators.email).
— Для поля password — обязательно и минимум 6 символов (Validators.minLength(6)).

2. Проверяем статус валидации в шаблоне

Валидаторы сами по себе — это как строгий учитель, который молча ставит двойки. Но пользователю нужно объяснить, что он сделал не так! Для этого мы можем проверить состояние поля и показать подсказку.

Пример: выводим ошибки под полями

<form [formGroup]="registerForm">
  <label>
    Email:
    <input formControlName="email">
  </label>
  <div *ngIf="email.invalid && email.touched" style="color: red;">
    <div *ngIf="email.errors?.['required']">Email обязателен!</div>
    <div *ngIf="email.errors?.['email']">Введите корректный email.</div>
  </div>

  <label>
    Пароль:
    <input type="password" formControlName="password">
  </label>
  <div *ngIf="password.invalid && password.touched" style="color: red;">
    <div *ngIf="password.errors?.['required']">Пароль обязателен!</div>
    <div *ngIf="password.errors?.['minlength']">
      Пароль должен быть не короче {{ password.errors?.['minlength'].requiredLength }} символов.
      Сейчас: {{ password.errors?.['minlength'].actualLength }}
    </div>
  </div>

  <button [disabled]="registerForm.invalid">Зарегистрироваться</button>
</form>

А в компоненте:

get email() {
  return this.registerForm.get('email')!;
}
get password() {
  return this.registerForm.get('password')!;
}

Пояснения:
email.invalid && email.touched — показываем ошибку только если поле уже трогали (а не сразу при загрузке).
email.errors?.['required'] — Angular кладёт ошибки в объект errors по ключу названия валидатора.
— Для minlength можно вывести, сколько символов не хватает.

3. Как работают валидаторы под капотом?

Каждый валидатор — это просто функция, которая проверяет значение и возвращает либо null (если всё хорошо), либо объект с ошибкой. Angular уже реализовал самые частые проверки за нас.

Вот, например, как выглядит Validators.required (упрощённо):

static required(control: AbstractControl): ValidationErrors | null {
  return control.value == null || control.value === ''
    ? { 'required': true }
    : null;
}

Если поле пустое — возвращает ошибку, иначе всё ок.

Как Angular узнаёт, что поле невалидно?

  • Каждый FormControl хранит свойство .valid (всё ок) и .invalid (что-то не так).
  • Ошибки доступны через .errors.
  • FormGroup становится невалидной, если хотя бы одно поле не проходит валидацию.

4. Полезные нюансы

Validators.required — обязательное поле

Это самый частый валидатор: запрещает отправлять форму, если поле пустое. Работает для строк, чисел, даже чекбоксов.

Примеры:

new FormControl('', Validators.required); // строка
new FormControl(false, Validators.required); // чекбокс

Если поле пустое ('', null, undefined, false для чекбокса) — будет ошибка 'required': true.

В шаблоне:

<div *ngIf="control.errors?.['required']">Поле обязательно для заполнения!</div>

Validators.email — проверка email

Проверяет, что значение похоже на email. Не ждите, что он проверит, существует ли такой ящик — только что строка похожа на "что-то@что-то.что-то".

Пример:

new FormControl('', [Validators.required, Validators.email]);

Если строка не подходит под email-паттерн — ошибка 'email': true.

В шаблоне:

<div *ngIf="control.errors?.['email']">Введите корректный email.</div>

Важно:
Этот валидатор не проверяет, что email реально существует, а только что написан по правилам.

Validators.minLength — минимальная длина

Ограничивает минимальное количество символов, которые пользователь должен ввести.

Пример:

new FormControl('', [Validators.required, Validators.minLength(8)]);

Если длина строки меньше 8 — ошибка 'minlength': { requiredLength: 8, actualLength: ... }

В шаблоне:

<div *ngIf="control.errors?.['minlength']">
  Минимальная длина — {{ control.errors?.['minlength'].requiredLength }} символов.
  Сейчас: {{ control.errors?.['minlength'].actualLength }}
</div>

Комбинирование валидаторов

Можно передать массив валидаторов, и Angular будет проверять их все:

new FormControl('', [
  Validators.required,
  Validators.email,
  Validators.minLength(10)
]);

Ошибки будут складываться в объект errors с соответствующими ключами.

Проверка валидности формы и её отправка

Обычно кнопку "Отправить" блокируют, если форма невалидна:

<button [disabled]="registerForm.invalid">Зарегистрироваться</button>

В методе отправки формы можно проверить:

onSubmit() {
  if (this.registerForm.invalid) {
    // Можно подсветить все поля
    this.registerForm.markAllAsTouched();
    return;
  }

  // Всё ок — отправляем данные!
  console.log(this.registerForm.value);
}

Таблица: основные встроенные валидаторы

Валидатор Описание Ошибка в errors Пример использования
Validators.required
Обязательное поле
{ required: true }
Validators.required
Validators.email
Корректный email
{ email: true }
Validators.email
Validators.minLength(n)
Минимальная длина строки
{ minlength: { ... } }
Validators.minLength(8)
Validators.maxLength(n)
Максимальная длина строки
{ maxlength: { ... } }
Validators.maxLength(20)
Validators.pattern(regex)
Проверка по регулярному выражению
{ pattern: { ... } }
Validators.pattern(/[0-9]+/)

5. Практический пример: форма регистрации

Давайте соберём всё вместе.

import { Component } from '@angular/core';
import { FormGroup, FormControl, Validators } from '@angular/forms';

@Component({
  selector: 'app-register-form',
  template: `
    <form [formGroup]="registerForm" (ngSubmit)="onSubmit()">
      <label>
        Email:
        <input formControlName="email">
      </label>
      <div *ngIf="email.invalid && email.touched" class="error">
        <div *ngIf="email.errors?.['required']">Email обязателен!</div>
        <div *ngIf="email.errors?.['email']">Некорректный email.</div>
      </div>

      <label>
        Пароль:
        <input type="password" formControlName="password">
      </label>
      <div *ngIf="password.invalid && password.touched" class="error">
        <div *ngIf="password.errors?.['required']">Пароль обязателен!</div>
        <div *ngIf="password.errors?.['minlength']">
          Минимум {{ password.errors?.['minlength'].requiredLength }} символов.
          Сейчас: {{ password.errors?.['minlength'].actualLength }}
        </div>
      </div>

      <button [disabled]="registerForm.invalid">Зарегистрироваться</button>
    </form>
  `,
  styles: [`
    .error { color: red; font-size: 0.9em; }
    input.ng-touched.ng-invalid { border: 1px solid red; }
  `]
})
export class RegisterFormComponent {
  registerForm = new FormGroup({
    email: new FormControl('', [Validators.required, Validators.email]),
    password: new FormControl('', [Validators.required, Validators.minLength(6)])
  });

  get email() { return this.registerForm.get('email')!; }
  get password() { return this.registerForm.get('password')!; }

  onSubmit() {
    if (this.registerForm.invalid) {
      this.registerForm.markAllAsTouched();
      return;
    }
    alert('Регистрация прошла успешно! Данные: ' + JSON.stringify(this.registerForm.value));
    // Здесь можно отправить данные на сервер
  }
}

6. Типичные ошибки при использовании валидаторов

Ошибка №1: Не показывают ошибки, пока пользователь не тронул поле.
Пользователь думает, что всё хорошо, а при отправке формы — сюрприз. Используйте свойство .touched или .dirty, чтобы ошибки появлялись только когда поле реально трогали.

Ошибка №2: Проверяют только .invalid без уточнения типа ошибки.
Если у поля несколько валидаторов, важно показывать конкретную ошибку, а не просто "Что-то не так".

Ошибка №3: Не вызывают .markAllAsTouched() при отправке формы.
Если пользователь сразу жмёт "Отправить", а поля не тронуты — ошибки не появятся. Вызовите markAllAsTouched(), чтобы подсветить всё.

Ошибка №4: Используют только Validators.required, забывая про формат.
Например, для email — обязательно добавляйте Validators.email, иначе "qwerty" пройдёт проверку.

Ошибка №5: Не блокируют кнопку, когда форма невалидна.
Пользователь может отправить пустую форму — и вы получите кучу пустых заявок. Всегда делайте [disabled]="form.invalid".

Ошибка №6: Слишком много проверок в шаблоне.
Лучше вынести доступ к контролам в геттеры компонента, чтобы не писать длинные выражения в шаблоне.

Ошибка №7: Не обновляют ошибки после программного изменения значений.
Если вы меняете значения формы в коде, иногда нужно вызвать updateValueAndValidity() для пересчёта ошибок.

Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ