Формы в Angular
Обработка пользовательского ввода с помощью форм — основа многих распространённых приложений.
Приложения используют формы, чтобы пользователи могли входить в систему, обновлять профиль, вводить конфиденциальную информацию и выполнять множество других задач по вводу данных.
Angular предлагает два разных подхода к обработке пользовательского ввода с помощью форм: реактивный и на основе шаблонов.
Оба подхода позволяют получать события ввода пользователя из представления, проверять введённые данные, создавать форму и модель данных, а также отслеживать изменения.
СОВЕТ: Если вы ищете новые Signal Forms, ознакомьтесь с нашим руководством по основам Signal Forms!
В этом руководстве приведена информация, которая поможет выбрать тип формы, наиболее подходящий для вашей ситуации. Здесь рассматриваются общие строительные блоки, используемые в обоих подходах. Также кратко описаны ключевые различия между ними и показано, как эти различия проявляются при настройке, передаче данных и тестировании.
Выбор подхода
Реактивные формы и формы на основе шаблонов по-разному обрабатывают данные формы и управляют ими. У каждого подхода есть свои преимущества.
| Формы | Подробности |
|---|---|
| Реактивные формы | Обеспечивают прямой и явный доступ к базовой объектной модели формы. По сравнению с формами на основе шаблонов они надёжнее: их проще масштабировать, повторно использовать и тестировать. Если формы играют ключевую роль в вашем приложении или вы уже используете реактивные шаблоны при его создании, выбирайте реактивные формы. |
| Формы на основе шаблонов | Используют директивы в шаблоне для создания базовой объектной модели и управления ею. Они подходят для добавления простой формы в приложение, например формы подписки на рассылку по электронной почте. Их легко добавить в приложение, но масштабируются они хуже, чем реактивные формы. Если требования к форме и её логика очень просты и могут полностью обрабатываться в шаблоне, формы на основе шаблонов могут стать хорошим выбором. |
Ключевые различия
В следующей таблице приведены основные различия между реактивными формами и формами на основе шаблонов.
| Реактивные | На основе шаблонов | |
|---|---|---|
| Настройка модели формы | Явная, создаётся в классе компонента | Неявная, создаётся директивами |
| Модель данных | Структурированная и неизменяемая | Неструктурированная и изменяемая |
| Передача данных | Синхронная | Асинхронная |
| Проверка формы | Функции | Директивы |
Масштабируемость
Если формы занимают центральное место в вашем приложении, масштабируемость очень важна. Возможность повторно использовать модели форм в разных компонентах имеет решающее значение.
Реактивные формы масштабируются лучше, чем формы на основе шаблонов. Они обеспечивают прямой доступ к базовому API форм и используют синхронную передачу данных между представлением и моделью данных, что упрощает создание крупных форм. Для тестирования реактивных форм требуется меньше настроек, а для корректной проверки обновлений и валидации формы не нужно глубоко разбираться в обнаружении изменений.
Формы на основе шаблонов предназначены для простых сценариев и хуже подходят для повторного использования. Они скрывают базовый API форм и используют асинхронную передачу данных между представлением и моделью данных. Абстракция форм на основе шаблонов влияет и на тестирование. Для корректного выполнения тестов необходимо вручную запускать обнаружение изменений, а настройка требует больше усилий.
Настройка модели формы
И реактивные формы, и формы на основе шаблонов отслеживают изменения значений между элементами ввода формы, с которыми взаимодействуют пользователи, и данными формы в модели компонента. В основе обоих подходов лежат общие строительные блоки, но способы создания и управления экземплярами общих элементов управления формы различаются.
Общие базовые классы форм
И реактивные формы, и формы на основе шаблонов построены на следующих базовых классах.
| Базовые классы | Подробности |
|---|---|
FormControl | Отслеживает значение и состояние проверки отдельного элемента управления формы. |
FormGroup | Отслеживает те же значения и состояние для набора элементов управления формы. |
FormArray | Отслеживает те же значения и состояние для массива элементов управления формы. |
ControlValueAccessor | Создаёт связующее звено между экземплярами Angular FormControl и встроенными элементами DOM. |
Настройка реактивных форм
В реактивных формах модель формы задаётся непосредственно в классе компонента. Директива [formControl] связывает явно созданный экземпляр FormControl с определённым элементом формы в представлении, используя внутренний адаптер значения.
В следующем компоненте с помощью реактивных форм реализовано поле ввода для одного элемента управления. В этом примере модель формы — это экземпляр FormControl.
import {Component} from '@angular/core';
import {FormControl, ReactiveFormsModule} from '@angular/forms';
@Component({
selector: 'app-reactive-favorite-color',
template: ` Favorite Color: <input type="text" [formControl]="favoriteColorControl" /> `,
imports: [ReactiveFormsModule],
})
export class FavoriteColorReactive {
favoriteColorControl = new FormControl('');
}
ВАЖНО: В реактивных формах источником истины является модель формы; через директиву [formControl] на элементе <input> она в любой момент времени предоставляет значение и состояние элемента формы.
Настройка форм на основе шаблонов
В формах на основе шаблонов модель формы неявная, а не явная. Директива NgModel создаёт экземпляр FormControl для заданного элемента формы и управляет им.
В следующем компоненте с помощью форм на основе шаблонов реализовано то же поле ввода для одного элемента управления.
import {Component, signal} from '@angular/core';
import {FormsModule} from '@angular/forms';
@Component({
selector: 'app-template-favorite-color',
template: ` Favorite Color: <input type="text" [(ngModel)]="favoriteColor" /> `,
imports: [FormsModule],
})
export class FavoriteColorTemplate {
favoriteColor = signal('');
}
ВАЖНО: В форме на основе шаблонов источником истины является шаблон. Директива NgModel автоматически управляет экземпляром FormControl.
Передача данных в формах
Если в приложении есть форма, Angular должен поддерживать синхронизацию представления с моделью компонента, а модели компонента — с представлением. Когда пользователи изменяют значения и делают выбор в представлении, новые значения должны отражаться в модели данных. Аналогично, когда программная логика изменяет значения в модели данных, эти значения должны отражаться в представлении.
Реактивные формы и формы на основе шаблонов по-разному обрабатывают передачу данных, поступающих от пользователя или в результате программных изменений. На следующих диаграммах показаны оба типа потока данных для каждого типа формы на примере поля ввода любимого цвета, определённого выше.
Передача данных в реактивных формах
В реактивных формах каждый элемент формы в представлении напрямую связан с моделью формы (экземпляром FormControl). Обновления из представления в модель и из модели в представление выполняются синхронно и не зависят от способа отображения пользовательского интерфейса.
На диаграмме передачи данных из представления в модель показано, как данные передаются при изменении значения поля ввода в представлении, в соответствии со следующими шагами:
- Пользователь вводит значение в элемент ввода — в данном случае любимый цвет синий.
- Элемент ввода формы генерирует событие "input" с последним значением.
- Слушающий события элемента ввода формы
ControlValueAccessorнемедленно передаёт новое значение экземпляруFormControl. - Экземпляр
FormControlпередаёт новое значение через ObservablevalueChanges. - Все подписчики Observable
valueChangesполучают новое значение.
Диаграмма «модель — представление» показывает, как программное изменение модели передается представлению с помощью следующих шагов.
- Пользователь вызывает метод
favoriteColorControl.setValue(), который обновляет значениеFormControl. - Экземпляр
FormControlпередает новое значение через наблюдаемый объектvalueChanges. - Все подписчики наблюдаемого объекта
valueChangesполучают новое значение. - Аксессор значения элемента управления, связанный с элементом ввода формы, обновляет значение элемента.
Поток данных в формах, управляемых шаблонами
В формах, управляемых шаблонами, каждый элемент формы связан с директивой, которая управляет моделью формы внутри себя.
Диаграмма «представление — модель» показывает, как передаются данные при изменении значения поля ввода в представлении. Процесс состоит из следующих шагов.
- Пользователь вводит Blue в элемент ввода.
- Элемент ввода генерирует событие "input" со значением Blue.
- Аксессор значения элемента управления, связанный с элементом ввода, вызывает метод
setValue()экземпляраFormControl. - Экземпляр
FormControlпередает новое значение через наблюдаемый объектvalueChanges. - Все подписчики наблюдаемого объекта
valueChangesполучают новое значение. - Аксессор значения элемента управления также вызывает метод
NgModel.viewToModelUpdate(), который генерирует событиеngModelChange. - Поскольку в шаблоне компонента для свойства
favoriteColorиспользуется двусторонняя привязка данных, свойствуfavoriteColorкомпонента присваивается значение, переданное событиемngModelChange(Blue).
Диаграмма передачи данных от модели к представлению показывает, как данные проходят от модели к представлению, когда значение favoriteColor меняется с Синего на Красный, в ходе следующих шагов
- Значение
favoriteColorобновляется в компоненте. - Начинается обнаружение изменений.
- Во время обнаружения изменений для экземпляра директивы
NgModelвызывается хук жизненного циклаngOnChanges, поскольку изменилось значение одного из входных параметров. - Метод
ngOnChanges()ставит в очередь асинхронную задачу для установки значения внутреннего экземпляраFormControl. - Обнаружение изменений завершается.
- При следующем такте выполняется задача установки значения экземпляра
FormControl. - Экземпляр
FormControlпередает последнее значение через observablevalueChanges. - Все подписчики observable
valueChangesполучают новое значение. - Аксессор значения элемента управления обновляет элемент ввода формы в представлении, передавая ему последнее значение
favoriteColor.
ПРИМЕЧАНИЕ: NgModel запускает второй цикл обнаружения изменений, чтобы избежать ошибок ExpressionChangedAfterItHasBeenChecked, поскольку изменение значения происходит во входной привязке.
Изменяемость модели данных
Метод отслеживания изменений влияет на эффективность вашего приложения.
| Формы | Подробности |
|---|---|
| Реактивные формы | Поддерживайте чистоту модели данных, предоставляя её в виде неизменяемой структуры данных. Каждый раз, когда в модели данных происходит изменение, экземпляр FormControl возвращает новую модель данных, а не обновляет существующую. Это позволяет отслеживать отдельные изменения модели данных с помощью observable-контрола. Обнаружение изменений работает эффективнее, поскольку обновлять данные нужно только при отдельных изменениях. Поскольку обновления данных следуют реактивным шаблонам, вы можете интегрировать операторы observable для преобразования данных. |
| Формы, управляемые шаблонами | Используйте изменяемость и двустороннюю привязку данных, чтобы обновлять модель данных в компоненте по мере изменений в шаблоне. Поскольку при использовании двусторонней привязки данных отдельные изменения модели данных не отслеживаются, обнаружение изменений менее эффективно определяет, когда требуются обновления. |
Разница показана в предыдущих примерах с элементом ввода любимого цвета.
- В реактивных формах экземпляр
FormControlвсегда возвращает новое значение при обновлении значения контрола - В формах, управляемых шаблонами, свойство любимого цвета всегда изменяется на новое значение
Проверка форм
Проверка — неотъемлемая часть управления любым набором форм. Angular предоставляет набор встроенных валидаторов, а также возможность создавать собственные валидаторы, будь то проверка обязательных полей или запрос к внешнему API для проверки существующего имени пользователя.
| Формы | Подробности |
|---|---|
| Реактивные формы | Определяйте собственные валидаторы как функции, получающие контрол для проверки |
| Формы, управляемые шаблонами | Связаны с директивами шаблона; необходимо предоставлять собственные директивы-валидаторы, оборачивающие функции проверки |
Дополнительную информацию см. в разделе Проверка форм.
Тестирование
Тестирование играет важную роль в сложных приложениях. Более простая стратегия тестирования полезна для проверки корректной работы форм. Реактивные формы и формы, управляемые шаблонами, в разной степени зависят от отрисовки пользовательского интерфейса при выполнении проверок на основе изменений контролов и полей формы. В следующих примерах показан процесс тестирования реактивных форм и форм, управляемых шаблонами.
Тестирование реактивных форм
Реактивные формы обеспечивают относительно простую стратегию тестирования, поскольку предоставляют синхронный доступ к форме и моделям данных, а также позволяют тестировать их без отрисовки пользовательского интерфейса. В этих тестах состояние и данные запрашиваются и изменяются через контрол без взаимодействия с циклом обнаружения изменений.
В следующих тестах используются компоненты любимого цвета из предыдущих примеров, чтобы проверить потоки данных от представления к модели и от модели к представлению для реактивной формы.
Проверка потока данных от представления к модели
В первом примере выполняются следующие действия для проверки потока данных от представления к модели.
- Найдите в представлении элемент ввода формы и создайте для теста пользовательское событие "input".
- Задайте для ввода новое значение Red и отправьте событие "input" элементу ввода формы.
- Убедитесь, что значение
favoriteColorControlкомпонента совпадает со значением элемента ввода.
it('should update the value of the input field', () => {
const input = fixture.nativeElement.querySelector('input');
const event = createNewEvent('input');
input.value = 'Red';
input.dispatchEvent(event);
expect(fixture.componentInstance.favoriteColorControl.value).toEqual('Red');
});
В следующем примере выполняются действия для проверки потока данных от модели к представлению.
- Используйте
favoriteColorControl, экземплярFormControl, чтобы задать новое значение. - Найдите в представлении элемент ввода формы.
- Убедитесь, что новое значение, заданное для контрола, совпадает со значением элемента ввода.
it('should update the value in the control', () => {
component.favoriteColorControl.setValue('Blue');
const input = fixture.nativeElement.querySelector('input');
expect(input.value).toBe('Blue');
}); Тестирование форм, управляемых шаблонами
Написание тестов для форм, управляемых шаблонами, требует подробного знания процесса обнаружения изменений и понимания того, как директивы выполняются в каждом цикле, чтобы убедиться, что элементы запрашиваются, тестируются или изменяются в нужное время.
В следующих тестах используются упомянутые ранее компоненты любимого цвета, чтобы проверить потоки данных от представления к модели и от модели к представлению для формы, управляемой шаблонами.
Следующий тест проверяет поток данных от представления к модели.
it('should update the favorite color in the component', async () => {
const input = fixture.nativeElement.querySelector('input');
const event = createNewEvent('input');
input.value = 'Red';
input.dispatchEvent(event);
await fixture.whenStable();
expect(component.favoriteColor()).toEqual('Red');
});
Ниже приведены действия, выполняемые в тесте потока данных от представления к модели.
- Найдите в представлении элемент ввода формы и создайте для теста пользовательское событие "input".
- Задайте для ввода новое значение Red и отправьте событие "input" элементу ввода формы.
- Запустите обнаружение изменений с помощью тестового стенда.
- Убедитесь, что значение свойства компонента
favoriteColorсовпадает со значением элемента ввода.
Следующий тест проверяет поток данных от модели к представлению.
it('should update the favorite color on the input field', async () => {
component.favoriteColor.set('Blue');
await fixture.whenStable();
const input = fixture.nativeElement.querySelector('input');
expect(input.value).toBe('Blue');
});
Ниже приведены действия, выполняемые в тесте потока данных от модели к представлению.
- Используйте экземпляр компонента, чтобы задать значение свойства
favoriteColor. - Запустите обнаружение изменений с помощью тестового стенда.
- Используйте
await fixture.whenStable(), чтобы дождаться следующей отрисовки. - Найдите в представлении элемент ввода формы.
- Убедитесь, что значение элемента ввода совпадает со значением свойства
favoriteColorв экземпляре компонента.
Следующие шаги
Дополнительные сведения о реактивных формах см. в следующих руководствах:
Дополнительные сведения о формах, управляемых шаблонами, см. в следующих руководствах:
Super-powered by Google ©2010–2025.
Code licensed under an MIT-style License. Documentation licensed under CC BY 4.0.
https://angular.dev/guide/forms