Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple components binding with the same reactive form control update issue

In some situations, we could need to have multiple form components binded to the same form control. And I'm confused by the angular way of handling this case:

When changing one of the components value, the form value is changed but not the other components values.

The workaround I did in this case is to patch the from with the form value, which is ugly:

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

Here is a stackblitz demo for my issue, I added the workaround for the input change not the select for better understanding.

Is there an elegant way to handle this case with angular reactive forms?

like image 687
ibenjelloun Avatar asked Apr 19 '18 08:04

ibenjelloun


People also ask

When using Reactive forms which is the recommended forms of binding data to a controller?

You can use [(ngModel)] with Reactive forms. This will a completely different directive than the one that would be used without the formControlName . With reactive forms, it will be the FormControlNameDirective . Without the formControlName , the NgModel directive would be used.

Is Reactive form two way binding?

We can perform Two way binding in Template driven forms but there is no two way binding in Reactive forms. Angular provides the methods to update the values from the component class. Reactive forms are used on complex cases, like dynamic forms element, dynamic validations etc.

Why are Reactive forms synchronous?

Since the Reactive form is predictable it accesses the data model synchronously. The forms are created around measurable sources and the inputs and values are given as the sources of input values that can be accessed synchronously.


1 Answers

A nice reactive solution which would not require adding any (change) listeners, would be to create two separate name controls, and keep them in sync by subscribing to valueChanges stream.

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>

Live demo

like image 81
Tomasz Kula Avatar answered Oct 09 '22 06:10

Tomasz Kula