Группы форм и массивы

FormGroup — базовая структура реактивных форм Angular, предназначенная для объединения нескольких элементов управления (FormControl) в единый объект. Такая группа отражает логическую модель данных и позволяет управлять состоянием формы как целого.

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

const profileForm = new FormGroup({
  firstName: new FormControl(''),
  lastName: new FormControl(''),
  email: new FormControl('')
});

Каждое поле формы представлено ключом объекта, а его значением — экземпляр FormControl. В результате profileForm.value возвращает объект с актуальными данными формы.

Ключевые возможности FormGroup:

  • централизованное управление значениями;
  • агрегация состояния (valid, invalid, touched, dirty);
  • применение валидаторов на уровне всей группы;
  • вложенность групп для сложных структур данных.

Инициализация через FormBuilder

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

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

constructor(private fb: FormBuilder) {}

profileForm = this.fb.group({
  firstName: [''],
  lastName: [''],
  email: ['']
});

Массив в значении поля может содержать:

  1. начальное значение;
  2. синхронные валидаторы;
  3. асинхронные валидаторы.
email: ['', [Validators.required, Validators.email]]

Вложенные FormGroup

Сложные формы часто отражают иерархическую структуру данных. Для этого применяется вложенность FormGroup.

profileForm = this.fb.group({
  name: this.fb.group({
    firstName: [''],
    lastName: ['']
  }),
  contacts: this.fb.group({
    email: [''],
    phone: ['']
  })
});

Доступ к вложенным элементам осуществляется через метод get с использованием пути:

this.profileForm.get('name.firstName');

Такой подход обеспечивает строгую связь между моделью формы и бизнес-логикой приложения.


Валидаторы на уровне группы

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

const passwordGroup = this.fb.group(
  {
    password: [''],
    confirmPassword: ['']
  },
  { validators: passwordMatchValidator }
);

Пример пользовательского валидатора:

function passwordMatchValidator(group: FormGroup) {
  const pass = group.get('password')?.value;
  const confirm = group.get('confirmPassword')?.value;
  return pass === confirm ? null : { passwordMismatch: true };
}

Такой валидатор влияет на состояние всей группы, а не отдельных полей.


FormArray: динамические наборы элементов

FormArray предназначен для работы с коллекциями однотипных элементов формы, количество которых заранее неизвестно.

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

skills = new FormArray([
  new FormControl('JavaScript'),
  new FormControl('TypeScript')
]);

Чаще FormArray используется в составе FormGroup:

profileForm = this.fb.group({
  skills: this.fb.array([])
});

Получение массива:

get skills(): FormArray {
  return this.profileForm.get('skills') as FormArray;
}

Добавление и удаление элементов FormArray

Динамическое управление элементами — ключевая особенность FormArray.

this.skills.push(this.fb.control(''));

Удаление по индексу:

this.skills.removeAt(index);

Очистка всего массива:

this.skills.clear();

Каждый элемент массива может быть как FormControl, так и FormGroup, что позволяет описывать сложные повторяющиеся структуры.


FormArray из FormGroup

Частый сценарий — массив объектов, каждый из которых содержит несколько полей.

addresses = this.fb.array([
  this.fb.group({
    city: [''],
    street: [''],
    zip: ['']
  })
]);

Добавление нового адреса:

this.addresses.push(
  this.fb.group({
    city: [''],
    street: [''],
    zip: ['']
  })
);

В таком виде FormArray полностью повторяет структуру массива объектов модели данных.


Связывание FormArray с шаблоном

Для отображения массива элементов используется директива formArrayName в сочетании с *ngFor.

<div formArrayName="skills">
  <div *ngFor="let skill of skills.controls; let i = index">
    <input [formControlName]="i">
  </div>
</div>

Для массива групп:

<div formArrayName="addresses">
  <div *ngFor="let address of addresses.controls; let i = index" [formGroupName]="i">
    <input formControlName="city">
    <input formControlName="street">
    <input formControlName="zip">
  </div>
</div>

Шаблон строго повторяет структуру формы, заданную в коде.


Управление состоянием групп и массивов

FormGroup и FormArray предоставляют методы для управления состоянием:

  • disable() / enable() — блокировка и разблокировка;
  • markAsTouched() / markAsUntouched() — управление флагами взаимодействия;
  • reset() — сброс значений и состояния;
  • patchValue() — частичное обновление данных;
  • setValue() — строгое обновление всей структуры.
this.profileForm.patchValue({
  name: { firstName: 'Ivan' }
});

patchValue особенно полезен при работе с неполными данными, например при загрузке с сервера.


Проверка и обработка ошибок

Состояние валидности доступно как на уровне отдельных элементов, так и групп:

this.profileForm.valid
this.skills.at(0).invalid

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

this.profileForm.get('email')?.errors

Ошибки групповых валидаторов:

this.passwordGroup.errors?.passwordMismatch

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


Архитектурные преимущества использования FormGroup и FormArray

  • строгая типизация структуры формы;
  • предсказуемое управление состоянием;
  • легкая сериализация данных;
  • масштабируемость при росте сложности интерфейса;
  • удобная интеграция с сервисами и API.

Группы форм и массивы являются фундаментом для построения сложных, динамических и надежных форм в Angular, обеспечивая четкое разделение структуры данных, логики валидации и отображения.