JavaRush /Курсы /Модуль 4: Node.js, Next.js и Angular /Формы в Angular — отличие Template-driven и Reactive Form...

Формы в Angular — отличие Template-driven и Reactive Forms

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

1. Template-driven Forms

Форма — это не просто набор <input> и <button>. Это способ структурировать ввод пользователя, валидировать данные, отображать ошибки, собирать информацию для отправки на сервер и многое другое. В современных приложениях формы встречаются повсюду: регистрация, авторизация, фильтры, поиск, настройки профиля, обратная связь — и этот список можно продолжать до бесконечности.

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

  • Template-driven forms — формы, управляемые через шаблон (HTML).
  • Reactive forms — формы, управляемые через TypeScript-код (модель).

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

Краткое описание

Template-driven формы (или "шаблонные формы") — это подход, при котором почти вся логика формы (валидация, сбор данных, обработка ошибок) описывается прямо в HTML-шаблоне компонента. TypeScript-код компонента обычно минимален. Angular сам под капотом связывает шаблон с моделью.

Главная идея:
Вы описываете структуру формы в HTML, а Angular автоматически создаёт "форменную модель" по вашим атрибутам.

Когда использовать Template-driven формы?

  • Простые формы (2–10 полей), без сложной вложенности.
  • Быстрые прототипы, формы с минимальной валидацией.
  • Когда хочется писать минимум кода на TypeScript.

Как это выглядит?

Шаг 1: Импорт FormsModule

import { FormsModule } from '@angular/forms';

@NgModule({
  imports: [
    FormsModule,
    // ... другие модули
  ]
})
export class AppModule { }

Шаг 2: Шаблон формы

<form #userForm="ngForm" (ngSubmit)="onSubmit(userForm)">
  <label>
    Имя:
    <input name="name" ngModel required>
  </label>
  <label>
    Email:
    <input name="email" ngModel email>
  </label>
  <button type="submit">Отправить</button>
</form>

Шаг 3: Компонент

export class UserFormComponent {
  onSubmit(form: any) {
    console.log(form.value); // { name: '...', email: '...' }
  }
}

Как это работает?

  • Атрибут ngModel связывает поле ввода с моделью Angular.
  • Angular сам создаёт объект формы, который можно получить через #userForm="ngForm".
  • Валидация (например, required, email) указывается прямо в HTML.

Пример двухсторонней привязки

<input [(ngModel)]="userName" name="userName">

Всё просто и похоже на магию! Но магия работает только для несложных случаев.

2. Reactive Forms — формы, управляемые моделью

Reactive Forms (или "реактивные формы", или "модельные формы") — это подход, при котором вся логика формы (структура, валидация, значения, ошибки) описывается в TypeScript-коде компонента. Шаблон становится максимально "глупым" — он только отображает поля и ошибки.

Главная идея:
Вы явно создаёте модель формы в коде, полностью контролируете её состояние и реакцию на изменения.

Когда использовать Reactive Forms?

  • Сложные формы (много полей, вложенность, динамические поля).
  • Требуется сложная кастомная валидация (например, асинхронная проверка на сервере).
  • Нужно отслеживать изменения в форме (реагировать на каждое нажатие).
  • Когда форма может меняться динамически (например, добавление/удаление полей).

Как это выглядит?

Шаг 1: Импорт ReactiveFormsModule

import { ReactiveFormsModule } from '@angular/forms';

@NgModule({
  imports: [
    ReactiveFormsModule,
    // ... другие модули
  ]
})
export class AppModule { }

Шаг 2: Компонент

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

export class UserFormComponent {
  userForm = new FormGroup({
    name: new FormControl('', Validators.required),
    email: new FormControl('', [Validators.required, Validators.email])
  });

  onSubmit() {
    console.log(this.userForm.value); // { name: '...', email: '...' }
  }
}

Шаг 3: Шаблон

<form [formGroup]="userForm" (ngSubmit)="onSubmit()">
  <label>
    Имя:
    <input formControlName="name">
  </label>
  <label>
    Email:
    <input formControlName="email">
  </label>
  <button type="submit">Отправить</button>
</form>

Как это работает?

  • Вы явно создаёте структуру формы через FormGroup и FormControl.
  • Валидация задаётся в коде.
  • В шаблоне используется директива [formGroup] и formControlName.
  • Все данные, ошибки, состояние доступны через объект формы (userForm).

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

Сравнение Template-driven и Reactive Forms

Template-driven Reactive Forms
Где описывается? В шаблоне (HTML) В TypeScript-коде
Модуль FormsModule ReactiveFormsModule
Двусторонняя связь
[(ngModel)]
Нет (односторонняя)
Сложность Просто, "магия" Явно, больше кода
Валидация В шаблоне (атрибуты) В коде (
Validators
)
Динамические поля Сложно Легко
Тестируемость Сложнее Легко
Работа с вложенными структурами Ограничена Удобно
Асинхронная валидация Сложно Просто

Аналогия
Template-driven — вы пишете всё на HTML, а Angular под капотом волшебно связывает форму с моделью. Это как автоматическая коробка передач: удобно, пока не начались пробки и горки.
Reactive Forms — вы управляете каждым аспектом формы из кода. Это как механика: чуть сложнее, но полная свобода и контроль.

Когда какой подход выбирать?

  • Template-driven — если форма простая (несколько полей), не требуется сложная логика, хочется меньше кода. Отлично для быстрых прототипов, обратной связи, простых фильтров.
  • Reactive Forms — если форма сложная, с динамическими полями, вложенными группами, нужна сложная валидация, асинхронные проверки, интеграция с сервисами, тестирование. Это стандарт для всего серьёзного.

Совет:
В реальных проектах 90% сложных форм делают на Reactive Forms. Template-driven формы — это как блокнот: удобно для быстрых заметок, но не для написания романа.

4. Практика: Пример простой формы двумя способами

Задача: Форма регистрации с полями "Имя", "Email", "Пароль"

Template-driven вариант

Шаблон:

<form #regForm="ngForm" (ngSubmit)="onSubmit(regForm)">
  <label>
    Имя:
    <input name="name" ngModel required>
  </label>
  <div *ngIf="regForm.submitted && regForm.controls.name?.invalid">
    Имя обязательно!
  </div>

  <label>
    Email:
    <input name="email" ngModel required email>
  </label>
  <div *ngIf="regForm.submitted && regForm.controls.email?.invalid">
    Введите корректный email!
  </div>

  <label>
    Пароль:
    <input name="password" ngModel required minlength="6" type="password">
  </label>
  <div *ngIf="regForm.submitted && regForm.controls.password?.invalid">
    Пароль должен быть не менее 6 символов!
  </div>

  <button type="submit">Зарегистрироваться</button>
</form>

Компонент:

export class RegisterComponent {
  onSubmit(form: any) {
    if (form.valid) {
      // Отправляем данные на сервер
      console.log(form.value);
    }
  }
}

Reactive Forms вариант

Компонент:

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

export class RegisterComponent {
  regForm = new FormGroup({
    name: new FormControl('', Validators.required),
    email: new FormControl('', [Validators.required, Validators.email]),
    password: new FormControl('', [Validators.required, Validators.minLength(6)])
  });

  onSubmit() {
    if (this.regForm.valid) {
      // Отправляем данные на сервер
      console.log(this.regForm.value);
    }
  }
}

Шаблон:

<form [formGroup]="regForm" (ngSubmit)="onSubmit()">
  <label>
    Имя:
    <input formControlName="name">
  </label>
  <div *ngIf="regForm.get('name')?.invalid && regForm.get('name')?.touched">
    Имя обязательно!
  </div>

  <label>
    Email:
    <input formControlName="email">
  </label>
  <div *ngIf="regForm.get('email')?.invalid && regForm.get('email')?.touched">
    Введите корректный email!
  </div>

  <label>
    Пароль:
    <input formControlName="password" type="password">
  </label>
  <div *ngIf="regForm.get('password')?.invalid && regForm.get('password')?.touched">
    Пароль должен быть не менее 6 символов!
  </div>

  <button type="submit">Зарегистрироваться</button>
</form>

5. Типичные ошибки при работе с формами в Angular

Ошибка №1: Смешивание Template-driven и Reactive Forms в одном компоненте.
Angular не любит, когда вы пытаетесь использовать ngModel и formControlName одновременно. Это приводит к ошибкам и странному поведению. Решение: выберите один подход для компонента.

Ошибка №2: Отсутствие импорта нужного модуля.
Если вы забыли импортировать FormsModule или ReactiveFormsModule в модуль — ничего работать не будет, а Angular будет ругаться на неизвестные директивы.

Ошибка №3: Неуникальные имена полей в Template-driven формах.
Каждое поле с ngModel должно иметь уникальный атрибут name, иначе Angular не сможет правильно построить модель формы.

Ошибка №4: Ожидание двусторонней привязки в Reactive Forms.
В Reactive Forms нет [(ngModel)]! Не пытайтесь использовать его вместе с formControlName.

Ошибка №5: Не инициализированные значения в Reactive Forms.
Если вы не передали начальное значение в FormControl, оно будет null или '' — не забывайте про это при работе с формой.

Ошибка №6: Игнорирование состояния поля.
Валидацию и ошибки показывайте только если поле уже было в фокусе (touched) или пользователь попытался отправить форму. Не пугайте пользователя красным цветом с самого начала.

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