меню

Signal Forms — это новая реализация форм в Angular. Однако Reactive Forms будут поддерживаться ещё долгое время, и существует уже много кода, который их использует. Поэтому важно иметь возможность применять обе реализации форм в одном приложении и даже в одной форме. Это позволяет нам мигрировать существующие формы шаг за шагом и повторно использовать существующий код.

Для этого Angular предоставляет два моста (bridge): SignalFormControl и compatForm. Первый позволяет использовать Signal Forms внутри Reactive Forms, а второй — Reactive Forms внутри Signal Forms. В этой статье я покажу, как применять оба моста и как смешивать их в одной форме.

На следующей схеме показан пример, который я здесь использую. Сплошные границы обозначают Signal Forms, а пунктирные — Reactive Forms:

Миграция на Angular Signal Forms: взаимодействие с Reactive Forms

SignalFormControl: Signal Forms внутри Reactive Forms

SignalFormControl, появившийся в Angular 21.2, можно использовать внутри Reactive Form. Он состоит из сигнала (Signal), валидируемого с помощью схемы Signal Forms. Таким образом, он является мостом (адаптером) между двумя мирами.

Этот новый класс используется подобно FormControl, но вместо реактивных валидаторов принимает схему Signal Forms:

	
protected readonly phoneNumber = new SignalFormControl('', (path) => {
  required(path);
});
	

Как и обычные контролы формы, он может быть помещён в FormGroup:

	
protected readonly passengerGroup = this.formBuilder.nonNullable.group({
  firstName: '',
  lastName: '',
  email: 'me@here.com',
  phoneNumber: this.phoneNumber,
});
	

С точки зрения FormGroup, SignalFormControl — это обычный контрол формы, реализующий стандартный интерфейс AbstractControl. Следовательно, состояние SignalFormControl распространяется наверх. Например, если SignalFormControl невалиден, вся FormGroup также становится невалидной.

То же самое относится и к свойству value. Например, при выводе значения passengerGroup в нашем примере мы видим, что оно содержит значение phoneNumber из SignalFormControl:

	
{
  "passenger": {
      "firstName": "John",
      "lastName": "Doe",
      "email": "john@doe.com",
      "phoneNumber": "133"
  }
}
	

В шаблоне SignalFormControl используется как обычный FormControl:

	
<fieldset [formGroup]="passengerGroup">
    <input formControlName="firstName" id="firstName" />
    <input formControlName="lastName" id="lastName" />
    <input formControlName="email" id="email" />

    
    <fieldset>
       <input formControlName="phoneNumber" id="phoneNumber" />
    </fieldset>
</fieldset>
	

Под капотом этот контрол использует сигнал. Чтобы получить его значение, можно обратиться к свойству sourceValue:

	
protected readonly fullPhoneNumber = computed(() => '+43 ' + this.phoneNumber.sourceValue());
	

compatForm: Reactive Forms внутри Signal Forms

В то время как SignalFormControl позволяет использовать Signal Forms внутри Reactive Forms, хелпер compatForm, доступный в Angular начиная с версии 21.0, позволяет использовать Reactive Forms внутри Signal Forms. Вы также можете смешивать оба моста при миграции большой формы.

Чтобы реализовать это, мы можем поместить passengerGroup из предыдущего раздела в сигнал:

	
protected readonly checkinFormModel = signal({
  ticketId: '',
  conditionsAccepted: false,
  passenger: this.passengerGroup,
});
	

Этот сигнал служит основой для Signal Form. Чтобы учесть passengerGroup, мы передаём её в compatForm вместо передачи в функцию form:

	
protected readonly checkinForm = compatForm(this.checkinFormModel, (path) => {
  required(path.ticketId);
});
	

Теперь мы можем связать отдельные части формы, используя типичные директивы Signal Forms и Reactive Forms:

	
<!-- Signal Form (compatForm) -->
<form>
    <input [formField]="checkinForm.ticketId" />

    
    <fieldset [formGroup]="passengerGroup">
        <input formControlName="firstName" id="firstName" />
        <input formControlName="lastName" id="lastName" />
        <input formControlName="email" id="email" />

        <!-- Signal Form (SignalFormControl) -->
        <fieldset>
          <input formControlName="phoneNumber" id="phoneNumber" />
        </fieldset>
    </fieldset>
    [...]

	

И здесь состояние формы также распространяется наверх. Если, например, phoneNumber или firstName невалидны, вся форма также станет невалидной.

Однако здесь нужно помнить, что наша модель формы на основе сигналов содержит FormGroup. Если мы хотим получить простой JavaScript-объект со всем содержимым формы, мы должны заменить эту FormGroup на её значение:

	
const { passenger, ...header } = this.checkinFormModel();

const checkinInfo = {
  ...header,
  passenger: {
    ...passenger.value,
  },
};
	

Заключение

С появлением Signal Forms Angular предлагает современную и гибкую альтернативу устоявшимся Reactive Forms. Благодаря предоставленным мостам оба подхода можно легко комбинировать, а существующие приложения мигрировать постепенно. Это обеспечивает разработку, ориентированную на будущее, без необходимости отказываться от проверенной функциональности.

Помощь сайту
ЮMoney:
4100 1180 7209 833
Карта Сбербанк:
2202 2080 6183 7127

Возможно, вам будет интересно

Angular Interceptor - перехватчик ошибок http

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

Angular Signals

Версия Angular 16 была выпущена в начале мая, и эта версия полна новых функций. Но одной из особенностей, о которой все говорят, является новая возможность - Сигналы. Это настоящий поворотный момент, который находится в стадии предварительного просмотра разработчиками и будет выпущен позже в этом году, в версии 17.

Формы. Шаблонный подход.

Работа с формами. Шаблонный подход (Template-driven)

Навигация. Передача данных событиями

Навигация в Angular на основе событий. Передача данных между вложенными компонентами с помощью событий в Angular