Angular Reactive forms : change vs valueChanges
Asked Answered
P

4

16

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?

Pyjamas answered 22/3, 2019 at 12:57 Comment(0)
N
37

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
  });
Nebulize answered 22/3, 2019 at 13:9 Comment(4)
That is the point. At this point i am creating forms. I am confused what should i use.Pyjamas
With the information so far, I think as far as the performance goes, (change) would be better as it gets called only once you blur away from the field. But again. without a more concrete example, it's hard to determine. Maybe create an example that can highlight the issue that you're facing and maybe I would be able to give better suggestions.Nebulize
I just have input of zip. On it's change i have to call service to get data like state, country, city...Pyjamas
@AnkurAkvaliya, I've updated my answer. Please check to see if that works for your use case.Nebulize
A
6

I would recommend to use Reactive Forms logic only. If you need to have a behaviour like (change) has, so that the value should only be emitted when blur is executed, you can set updateOn: 'blur' like this:

    this.fb.group({
      title: this.fb.control('', { updateOn: 'blur' }),
      description: '',
    })

or like this for the whole form:

    this.fb.group({
      title: '',
      description: '',
    },{updateOn: 'blur'})

Now you can subscribe to valueChanges:

this.form.valueChanges.subscribe(change=>{ console.log(change) })

In the first example, this will log changes in description every time you type something and for title only on leaving the input field.

Alix answered 3/8, 2022 at 13:26 Comment(1)
this is the right answer as the Angular documentation states that the source of truth for reactive forms is the model this.fb.group(...) while for template driven forms is the template.Starryeyed
P
3

This is case-to-case, but I find that things like checkboxes and radio buttons (true/false type controls) work better with the (change) handler and inputs and textfields are generally more suitable for valueChanges.

Although I'm not sure of performance, I assume this would be the ideal use case when dealing with this decision.

A good use case for valueChanges (for everything) is a complex form with a lot of ngIf logic. Sometimes these forms need a "chain reaction" of value changes to work correctly, in which case a (change) handler would be useless

Pedersen answered 13/8, 2019 at 14:48 Comment(0)
W
1

In case of an input (text) field, I would suggest to use either changeValues or value depending on your use case:

  • If you want to implement something similar to "Google's autocomplete feature", i.e., to provide (search) suggestions as you type → then use changeValues.
  • For every other case, I would use change.

This is just a rule of thumb, though, the devil is in the details.

Here is the code of a working example which I wrote while doing my own research/testing, it implements both approaches for the sake of comparison:

Wader answered 30/8, 2019 at 21:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.