angular / components

Component infrastructure and Material Design components for Angular
https://material.angular.io
MIT License
24.35k stars 6.74k forks source link

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

Open meblum opened 4 years ago

meblum commented 4 years ago

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

grantfeldman commented 4 years ago

I can see this happening as well.

crisbeto commented 4 years ago

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

meblum commented 4 years ago

Each input emits 2 times

alexschilpp commented 4 years ago

Having the same problem. Any news on this?

meblum commented 4 years ago

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.

zehavibarak commented 4 years ago

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

domsew commented 3 years ago

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

ibrahimAboelsuod commented 3 years ago

An Ugly workaround:

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

a less ugly workaround:

this.form.valueChanges.pipe(auditTime(0)).subscribe(...);
AlexSemenov commented 3 years ago

We are sure that both dates were chosen:

this.form.valueChanges.pipe(filter(value) => (value?.start_date && value?.end_date)).subscribe(....)
marcoshevaristo commented 2 years ago

I prefer the debouceTime approach for this kind of issue:

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

jdnichollsc commented 2 years ago

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

weilinzung commented 2 years ago

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

HerrDerb commented 1 year ago

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...