1

Something strange happening here. I have a form with 3 fields: a string and two objects. The both objects get values from mat-select. Here, if I select again the current value, will not be emitted any event. For the string, is another situation (named country)

The country field is a value get from one of three buttons as:

ts:

countries = ['en', 'de', 'es'];


countryChanged(country: string): void {
   this.form.patchValue({
     country
   });
}

html:

<button *ngFor="let country of countries" (click)="countryChanged(country)">
   {{country}}
</button>

now, the problem is that, even if I press the same button, it will trigger again the form valueChanges, even the value is the same as the previous.

this.form.valueChanges.pipe(
  distinctUntilChanged() // ?????
).subscribe(data => {
  // do stuff
});

Why distinctUntilChanged() don't do its work here?

I know I can avoid it simple, with an if condition inside countryChanged() method, but I want to understand why distinctUntilChanged() don't do its job.

countryChanged(country: string): void {
    if (country === this.form.get('country').value) {
       return;
    }

    this.form.patchValue({
       country
    });
}
AlleXyS
  • 2,476
  • 2
  • 17
  • 37
  • 1
    Because it's an object, what is compared in the `distinctUntilChanged()`, see https://stackoverflow.com/questions/37172395/rxjs-distinctuntilchanged-object-comparison – mat.hudak Oct 13 '21 at 10:56
  • damn, almost good, but if I don't use `startsWith` inside `valueChanges.pipe()`, `distinctUntilChanges` will not trigger for first time and will pass to `subscribe` function. And I really can not use `startsWith` here :)) – AlleXyS Oct 13 '21 at 11:11
  • Why can't you use `startsWith`? If I'm correct using `startsWith(null)` shouldn't be a problem. This null is not really set as a value and following `distinctUntilChanged` will handle it correctly. – mat.hudak Oct 14 '21 at 07:11
  • Sorry for later answer. I have some complex logique in form `valueChanges`, which can update route `params`, will update the url and emit an event to params subscriber (which is the first action of the component). Also have some other functions which will throw errors for undefined objects if I'll start with `null` values. Based on form inputs, I'll do some http requests (or sockets requests) or update router params and restart all the flow – AlleXyS Oct 26 '21 at 06:44

1 Answers1

2

Objects are reference types and "===" used by distinctUntilChanged will not work. You can compare the values of the previous and current emitted ones using JSON.stringify you will be able to compare the value of your two objects

.pipe(
  distinctUntilChanged((previous, current) => JSON.stringify(previous) === JSON.stringify(current))
)

Here is the code that will show you the difference between using JSON.stringify or without it

https://stackblitz.com/edit/typescript-hjq436?file=index.ts

Fateh Mohamed
  • 20,445
  • 5
  • 43
  • 52