Проверка формы в родительской форме Angular 2+

Скажем, у меня есть форма оформления заказа, которая содержит компонент дочернего адреса следующим образом

<form [formGroup]="checkoutForm">
  <input formControlName="fullName">
  /** more inputs **/
  <address-form></address-form>
  <button type="submit">Submit</button>
</form>

На данный момент у меня есть checkoutForm, подобный:

this.checkoutForm = this.formBuilder.group({
    fullName: ['', Validators.required]
}); 

Шаблон addressForm выглядит так:

<form [formGroup]="addressForm">
   <input formControlName="street">
   <input formControlName="town"
</form>

И построен как:

this.addressForm = this.formBuilder.group({
  street: ['', [Validators.required]],
  town: ['', Validators.required]
});

Теперь у меня есть проблема: я не знаю, как

1 - Проверяйте родительскую форму, только если дочерняя форма действительна.

2 - Проверяйте дочернюю форму при отправке родительской формы.

Единственный способ, которым я мог думать об этом, - это иметь @Output() addressResponse, который будет излучать this.addressForm.valueChanges с достоверностью и данными. Что-то вроде:

this.addressForm.valueChanges.subscribe(data => {
   let form = this.addressForm.valid ?  
         { valid: true, value: data }: 
         { valid: false, value: data };
   this.addressResponse.emit(form);
});

И компонент родительской формы может использовать эти переданные данные.

А также есть @Input() parentFormSubmitted, который я могу использовать для отображения ошибок в шаблоне AddressForm

   <input formControlName="town"
   <div *ngIf="town.hasError('required') && (parentFormSubmitted || town.dirty">Town is a required field</div>

Хотя это сработает, я не уверен, что это оптимальное решение. Мне было интересно, есть ли способ сделать что-то более реактивным. (Может быть, включить группу AddressForm в определение группы CheckoutForm? ...)


person callback    schedule 28.09.2017    source источник


Ответы (1)


Вы совершенно правы со своим комментарием:

Мне было интересно, есть ли способ сделать что-то более реактивным. (Может быть, включить группу AddressForm в определение группы CheckoutForm? ...)

Вы можете создать свою форму в родительском элементе и передать вложенную группу address своему дочернему элементу как @Input. Поскольку объекты в JS являются изменяемыми, вам не нужен EventEmitter для передачи каких-либо изменений вашему родительскому объекту из дочернего элемента, изменения будут обнаружены «автоматически», и вы, следовательно, можете выполнять все проверки из родительского элемента.

Итак, в родителе создайте свою форму, например:

this.checkoutForm = this.formBuilder.group({
  fullName: ['', [...]],
  address: this.formBuilder.group({
    street: ['', [...]],
    town: ['', [...]]
  })
})

затем в дочернем теге передайте address дочернему элементу как @Input:

<address-form [address]="checkoutForm.controls.address"></address-form>

В своем ребенке вы отмечаете @Input:

@Input() address: FormGroup;

и шаблон в дочернем будет выглядеть так:

<div [formGroup]="address">
  <input formControlName="street"><br>
  <!-- Validation messages -->
  <input formControlName="town">
  <!-- Validation messages -->
</div>

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

person AJT82    schedule 01.10.2017
comment
Спасибо за ответ @ AJT_82. Как бы я поступил, если бы у меня было два экземпляра адреса, которые указывают на один и тот же дочерний компонент в моей родительской форме. Придется ли мне определять две отдельные группы addressForm в основной группе checkoutForm? - person callback; 02.10.2017
comment
Возможно, вам тогда понадобится массив форм, в который вы можете вставить эти два адреса, или, если он является динамическим, и вы также можете динамически отправлять адреса. Примерно так: stackoverflow.com/a/43521492/6294072 - person AJT82; 02.10.2017
comment
Идея состоит в том, чтобы установить флажок для адреса, который будет присутствовать в DOM, но отображаться только тогда, когда флажок установлен. Вы рекомендуете formArray? - person callback; 02.10.2017
comment
Все зависит от обстоятельств. У вас по-прежнему более одной группы адресов? Если это так и число динамическое, используйте массив форм. Если вы знаете, что есть только два адреса, решать вам. Если бы я знал, что у меня всего две группы, я, возможно, выбрал бы две группы вместо массива форм, особенно если у вас есть какое-то условие, когда их показывать :) - person AJT82; 02.10.2017
comment
Спасибо, сэр. Ваши комментарии и указания были очень полезны - person callback; 02.10.2017