Angular Reactive forms : change vs valueChanges

Ankur Akvaliya picture Ankur Akvaliya · Mar 22, 2019 · Viewed 23.4k times · Source

I am using reactive forms in Angular 7.

I have many fields that are dependent on other fields.

What I am curious about of what should I use (change) or this.form.get("control_name").valueChanges?

For ex. if both will work on inputs then I want to know difference, pros & cons between them.

Which is better with performance?

Answer

SiddAjmera picture SiddAjmera · Mar 22, 2019

Let's just consider that what you're looking for is to listen to a change on an input tag of type="text"

In case of valueChanges

Since it is an Observable, it will fire with a new value. This value will be the changed value of the input field. And to listen to it, you will have to subscribe to the valueChanges Observable. Something like this:

this.form1.controls['name'].valueChanges.subscribe(change => {
  console.log(change); // Value inside the input field as soon as it changes
});

In the case of (change) event

In case of the change event, for input tag, the change event will only fire once you blur away from that input field. Also, in this case, you'll get the $event Object. And from that $event Object, you'll have to extract the field value.


So in code, this will look something like this:

import { Component } from '@angular/core';
import { FormGroup, FormBuilder } from '@angular/forms';

@Component({...})
export class AppComponent  {
  name = 'Angular';
  form1: FormGroup;
  form2: FormGroup;

  constructor(private fb: FormBuilder) {}

  ngOnInit() {
    this.form1 = this.fb.group({
      name: [],
      email: []
    });

    this.form2 = this.fb.group({
      name: [],
      email: []
    });

    this.form1.controls['name'].valueChanges.subscribe(change => {
      console.log(change);
    });
  }

  onForm2NameChange({ target }) {
    console.log(target.value);
  }

}

And in the Template:

<form [formGroup]="form1">
  <input type="text" formControlName="name">
  <input type="text" formControlName="email">
</form>

<hr>

<form [formGroup]="form2">
  <input type="text" formControlName="name" (change)="onForm2NameChange($event)">
  <input type="text" formControlName="email">
</form>

Here's a Working Sample StackBlitz for your ref.


NOTE: It completely depends on your use case as to which one would be more suitable.


UPDATE:

For your specific use case, I would suggest using RxJS Operators to get the job done. Something like this:

zipCodeFormControl
  .valueChanges
  .pipe(
    debounceTime(500),
    distinctUntilChanged(),
    switchMap(
      zipcode => getAddressFromZipcode(zipcode)
    ),
    map(res => res.actualResult)
  )
  .subscribe(addressComponents => {
    // Here you can extract the specific Address Components
    // that you want to auto fill in your form and call the patchValue method on your form or the controls individually
  });