web-dev-qa-db-fra.com

Liaison bidirectionnelle sous formes réactives

L'utilisation de Angular 2, la liaison bidirectionnelle est simple dans les formulaires basés sur des modèles - vous utilisez simplement la syntaxe de la boîte banane. Comment pourriez-vous reproduire ce comportement dans un formulaire basé sur un modèle?

Par exemple, voici une forme réactive standard. Supposons que c'est beaucoup plus compliqué qu'il n'y paraît, avec de nombreuses entrées et une logique métier, et donc plus approprié pour une approche basée sur un modèle qu'une approche basée sur un modèle.

export class ExampleModel {
    public name: string;
    // ... lots of other inputs
}

@Component({
    template: `
        <form [formGroup]="form">
            <input type="text" formControlName="name">
            ... lots of other inputs
        </form>

        <h4>Example values: {{example | json}}</h4>
    `
})
export class ExampleComponent {
    public form: FormGroup;
    public example: ExampleModel = new ExampleModel();

    constructor(private _fb: FormBuilder) {
        this.form = this._fb.group({
            name: [ this.example.name, Validators.required ]
            // lots of other inputs
        });
    }

    this.form.valueChanges.subscribe({
        form => {
            console.info('form values', form);
        }
    });
}

Dans subscribe(), je peux appliquer toutes sortes de logique aux valeurs de formulaire et les mapper si nécessaire. Cependant, je ne veux pas mapper chaque valeur d'entrée du formulaire. Je souhaite simplement voir les valeurs de l'ensemble du modèle employee au fur et à mesure de ses mises à jour, selon une approche similaire à celle de [(ngModel)]="example.name" et affichée dans le tube json du modèle. Comment puis-je accomplir cela?

44
ebakunin

Remarque: comme indiqué par @ Clouse24 , "Utilisation de Fromactif réactif avec ngModel est obsolète dans angular 6 et sera supprimé dans angular 7 " (ce qui signifie que la réponse ci-dessous ne sera plus prise en charge à partir de la version 7). Veuillez lire le lien pour voir le raisonnement en faveur de la dépréciation et voir quelles alternatives vous aurez.

Vous pouvez utiliser [(ngModel)] avec des formulaires réactifs.

<form [formGroup]="form">
  <input name="first" formControlName="first" [(ngModel)]="example.first"/>
  <input name="last" formControlName="last" [(ngModel)]="example.last"/>
</form>

export class App {
  form: FormGroup;
  example = { first: '', last: '' };

  constructor(builder: FormBuilder) {
    this.form = builder.group({
      first: '',
      last: ''
    })
  }
}

Plunker

Ce sera une directive complètement différente de celle qui serait utilisée sans la formControlName. Avec les formes réactives, ce sera la FormControlNameDirective. Sans la formControlName, la directive NgModel serait utilisée.

51
Paul Samsotha

Parfois, vous devrez peut-être combiner [(ngModel)] avec des formes réactives. Je pourrais être un contrôle d'entrée dont vous n'avez pas besoin dans le formulaire, mais vous devez quand même le lier au contrôleur. Ensuite, vous pouvez utiliser: [(ngModel)]="something" [ngModelOptions]="{standalone: true}"

10
Jens Alenius

Voici comment vous pouvez le résoudre:

Pour avoir le résultat de two-way-binding

J'utilise des "variables de modèle" locales et utilise le même formulaireContrôle pour les deux champs.

<form [formGroup]="formGroup">
  <input #myInput (input)="mySlider.value = myInput.value" type="number" formControlName="twoWayControl">

  <mat-slider #mySlider (input)="myInput.value = mySlider.value" formControlName="twoWayControl" min="1" max="100">
  </mat-slider>

</form>

Lorsque je souhaite par programme changer la valeur du modèle, j'utilise setValue() comme d'autres l'ont proclamé.

setTo33() {
  this.formGroup.get('twoWayControl').setValue(33);
}
2
Andre Elrico

Si vous souhaitez simplement afficher une valeur d'entrée, créez simplement une variable dans votre entrée et utilisez-la dans votre modèle.

    <h4>Example values: {{ name.value }}</h4>
1
Matheus Bueno
// Allow two way binding on the [(name)] from the parent component
private nameValue: string;
@Input()
get name() {
    return this.nameValue;
}
set name(values) {
    this.nameValue = values;
    this.nameChange.emit(this.nameValue);
}
@Output() nameChange = new EventEmitter<string>();

ngOnInit() {
    // Update local value and notify parent on control value change
    this.formControl.valueChanges.forEach(value => this.name = value));
}

ngOnChanges() {
    // Update local value on parent change
    this.formControl.setValue(this.expression);
}
0
Vedran