web-dev-qa-db-fra.com

Liaison de plusieurs composants avec le même problème de mise à jour du contrôle de formulaire réactif

Dans certaines situations, nous pourrions avoir besoin d'avoir plusieurs composants de formulaire liés au même contrôle de formulaire. Et je suis confus par la manière angular de gérer ce cas:

Lors de la modification de l'une des valeurs des composants, la valeur du formulaire est modifiée, mais pas les autres valeurs des composants.

La solution de contournement que j'ai faite dans ce cas est de corriger le from avec la valeur du formulaire, ce qui est laid:

this.form.patchValue(this.form.value);

Voici une démonstration de stackblitz pour mon problème , j'ai ajouté la solution de contournement pour le changement d'entrée et non la sélection pour une meilleure compréhension.

Existe-t-il une manière élégante de gérer ce cas avec angular formes réactives?

13
ibenjelloun

Une belle solution réactive qui ne nécessiterait pas l'ajout de (change) écouteurs, serait de créer deux contrôles de nom distincts et de les garder synchronisés en s'abonnant au flux valueChanges.

component.ts

import { Component, NgModule, ViewChild } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormBuilder, FormControl, FormGroup } from '@angular/forms';

@Component({
  selector: 'my-app',
  templateUrl: 'app.component.html'
})
export class AppComponent {
  form: FormGroup;

  constructor(private fb: FormBuilder) {
    this.form = this.fb.group({
      nameText: '',
      nameSelect: '',
    })

    const text = this.form.get('nameText');
    const select = this.form.get('nameSelect');

    text.valueChanges.subscribe(v => select.setValue(v, { emitEvent: false }));
    select.valueChanges.subscribe(v => text.setValue(v, { emitEvent: false }));
  }

}

component.html

<form [formGroup]="form">
  When you change the input, the select changes : <br>
  <input type="text" formControlName="nameText"><br>
  When you change the select, the input does not change : <br>
  <select formControlName="nameSelect">
    <option value="value1">value1</option>
    <option value="value2">value2</option>
  </select>
</form>

Démo en direct

10
Tomasz Kula

Je l'ai résolu en utilisant simplement les changements de valeur AbstractControl et les API setValue. Dans cette approche, vous n'avez pas besoin d'utiliser 2 contrôles de formulaire distincts, vous pouvez avoir un nombre illimité de composants liés au même contrôle de formulaire réactif.

this.form.get('formControlName').valueChanges.subscribe(value => {
    this.form.get('formControlName').setValue(value, { onlySelf: true, emitEvent: false, emitModelToViewChange: true });
  }, error => {}, () => { });

La clé ici est le paramètre d'options de setValue, cela empêchera l'exécution récurrente de valuesChanges jusqu'au débordement.

{ onlySelf: true, emitEvent: false, emitModelToViewChange: true }
1
DaMightyMouse