components icon indicating copy to clipboard operation
components copied to clipboard

bug(mat-date-range-picker): When used with angular forms, `valueChanges` is fired multiple times.

Open meblum opened this issue 4 years ago • 13 comments

Expected Behavior

Observable should emit only once per change

Actual Behavior

When listening on the formGroup, it fires 4 times, and when listening on start or end it fires 2 times

Bug demo

https://stackblitz.com/edit/angular-date-range-bug

Environment

  • Angular: 10
  • CDK/Material: 10

meblum avatar Jun 26 '20 15:06 meblum

I can see this happening as well.

grantfeldman avatar Jun 30 '20 02:06 grantfeldman

We need to assign the value also when the opposite input changes in order to trigger any validation that might depend on it.

crisbeto avatar Jul 16 '20 19:07 crisbeto

Each input emits 2 times

meblum avatar Jul 16 '20 20:07 meblum

Having the same problem. Any news on this?

alexschilpp avatar Sep 25 '20 09:09 alexschilpp

Unfortunately, I wouldn't expect it to be fixed soon. Only option as of now is to filter manually. Shouldn't be too hard with the observable operators.

meblum avatar Sep 25 '20 13:09 meblum

In addition, patching with emitEvent false will too cause multiple valueChanges to be triggered, as seen https://angular-pmxj3r-ipmezc.stackblitz.io

zehavibarak avatar Oct 11 '20 14:10 zehavibarak

I also faced this issue in Material 11. It is probably related to #20218. We need better integration with ReactiveForms.

domsew avatar Jan 27 '21 18:01 domsew

An Ugly workaround:

  private getFormValueChanges(): Observable<any> {
    return combineLatest([
      this.form.controls.start_date.valueChanges,
      this.form.controls.end_date.valueChanges
    ]).pipe(debounceTime(1000));
  }

ibrahimAboelsuod avatar Aug 31 '21 13:08 ibrahimAboelsuod

a less ugly workaround:

this.form.valueChanges.pipe(auditTime(0)).subscribe(...);

theorlovsky avatar Aug 31 '21 14:08 theorlovsky

We are sure that both dates were chosen:

this.form.valueChanges.pipe(filter(value) => (value?.start_date && value?.end_date)).subscribe(....)

AlexSemenov avatar Sep 07 '21 08:09 AlexSemenov

I prefer the debouceTime approach for this kind of issue:

this.form.valueChanges.pipe(debouceTime(500)).subscribe(...)

marcoshevaristo avatar Dec 03 '21 19:12 marcoshevaristo

Hello folks, hope you're doing well 😄

It's working fine without a debounce workaround:

this.form.valueChanges.pipe(
    distinctUntilChanged((prev, curr) => {
        return prev.startDate === curr.startDate && prev.endDate === curr.endDate;
    }),
).subscribe(res=>{
    console.log("range Change", res)
})

Happy coding! <3

jdnichollsc avatar Mar 09 '22 17:03 jdnichollsc

Same issue still with ng14 https://github.com/angular/components/issues/20218#issuecomment-1262584283

weilinzung avatar Sep 29 '22 18:09 weilinzung

still same issue. When selecting a new start date, two events get fired. the problem with this is that the first event still contains the old end date, the second event finally sets the end date to null. But like this, it is nearly impossible to filter out the first event, as the date range is valid and not distinctable from a final range selection.

first event --> {startDate: Tue Jul 11 2023 00:00:00 GMT+0200 (Mitteleuropäische Sommerzeit), endDate: Tue Jul 25 2023
second event --> 00:00:00 GMT+0200 (Mitteleuropäische Sommerzeit}
tap.js:17 {startDate: Tue Jul 11 2023 00:00:00 GMT+0200 (Mitteleuropäische Sommerzeit), endDate: null}

It seems that nobody cares that this thing is broken...

HerrDerb avatar Jul 25 '23 06:07 HerrDerb