components icon indicating copy to clipboard operation
components copied to clipboard

Bug: Datepicker value change event fires when changing min value of it

Open gogakoreli opened this issue 6 years ago • 13 comments

Bug, feature request, or proposal:

Bug

What is the expected behavior?

I am not sure it is expected to behave like that or not, but I think that changing min value of datepicker shouldn't fire value changes event of the form group. I changed value of min date inside subscribe method because I want to have mindate dynamically updated. I checked two conditions one with the formgroup where it happens twice all the time and another condition using just formcontrol this issue happens only first time. If I comment out the update of the mindate inside subscribe everything will be okay

What is the current behavior?

Form Group value change happens when changing Datepicker min value via two way binding, Min value update happens inside Subscribe method. This issue causes to fire valuechanges twice

What are the steps to reproduce?

Reproduction is StackBlitz using the formgroup https://stackblitz.com/edit/datepicker-min-date-bug?file=app/datepicker-min-max-example.ts

What is the use-case or motivation for changing an existing behavior?

I think something is odd because different conditions behave differently ( for example as I stated above about formcontrol vs formgroup)

Which versions of Angular, Material, OS, TypeScript, browsers are affected?

Angular Material 5.0.0-rc3

gogakoreli avatar Jan 09 '18 08:01 gogakoreli

@gogakoreli ,

I had the same problem and I used a simple workaround, a filter to simulate the min. This way, valuechanges isn't fired twice.

I added the filter to the input matDatepickerFilter.

<input [matDatepickerFilter]="minFilter"...

minFilter = (d: Date): boolean => {
  const from = new Date(this.form.get('curDate').value);
  if ( d < from ) {
    return false;
  }
  return true;
}

Here's your modified example: https://stackblitz.com/edit/datepicker-min-date-bug-53war2

Msimoneau avatar Feb 06 '18 17:02 Msimoneau

Thank you that solves it 😄 It is interesting why [min] binding behaves differently

gogakoreli avatar Feb 07 '18 06:02 gogakoreli

something to note though: doing it with a filter this way is less efficient, especially for year and multiyear view and it allows the user to navigate arbitrarily far past the min and max (just everything will show as grayed out) min/max actually prevent navigating beyond that page

mmalerba avatar Feb 07 '18 18:02 mmalerba

I faced a similar issue, where changes of min, max or matDatepickerFilter tiggered a valueChange. I tried to track down the issue and it seems like the problem is the interaction between the datepicker and the formcontrol: The MatDatepickerInput is a Validator and calls the validatorOnChange-callback, whenever min, max or matDatepickerFilter changes. In setUpControl in angular/forms, the validatorOnChange-callback is set and it calls updateValueAndValidity, which causes the value change event.

probert94 avatar Sep 30 '19 14:09 probert94

Any news on this? Is this issue fixed ?

masoudtahmasebi93 avatar Feb 03 '21 13:02 masoudtahmasebi93

the issue was new Date() will be changed when min and max call every time so don't add new Date() directly minfilter(){ return new Date()//don't do like this }

//do like this currentDate=new Date(); minfilter(){ return this.currentDate; }

Ajiharan avatar Feb 24 '21 07:02 Ajiharan

I think I got hit by the same issue. I was trying to use Reactive Forms and valueChanges to watch for any changes in the FormGroup. Seems that just setting min triggers two redundant valueChanges events due to revalidating start & end dates.

https://stackblitz.com/edit/angular-ivy-hnvpqd?file=src/app/app.component.ts

csvn avatar Sep 08 '21 18:09 csvn

I had the same problem, a simple workaround I used, was to check if the value was actually changed when the valueChanges was triggered. You can achieve this by:

this.FormGroup.controls.dateField.valueChanges.subscribe(value => {

//FormGroup.value container the previous value and value contains the changed value
//if previous value and current value are same then no changed occured. Do Nothing
        if (this.FormGroup.value.dateField == value){ 
          return;
        }
//Code when value actually changes...
}

grsubin avatar Apr 07 '23 13:04 grsubin

Angular 16.2.0 - the issue is still relevant.

serg-mois-capital avatar Aug 14 '23 12:08 serg-mois-capital

first() rxjs operator solved my issue. My piece of code looks something like this

this.form.get('name')?.valueChanges
      .pipe
      (
        first(),
        debounceTime(500),
        distinctUntilChanged(),
        startWith(''),
        filter(value => value.length > 2),
        tap(value => {
          this.valueSubject.next(value);
        }),
        switchMap(value => this.userService.findAll({
            name: value,
            limit: NUMBER_OF_ROWS_LIMIT,
            role: UserRole.PARENT,
          }),
        ),
        takeUntil(this.destroySubject),
      )
      .subscribe({
        next: (response: { data: User[]; meta: { total_count: number } }) => {
          if (!response) {
            return;
          }

          this.state.usersLoaded(response);
        },
      });

xbisa avatar Aug 26 '23 18:08 xbisa

Still relevant. Setting a min or max does not change the control value, so the valueChanges Observable on the control should not emit a new value.

igoraugustynski avatar May 08 '24 06:05 igoraugustynski

Why don't you just use the filter RxJS operator?

-------- Oprindelig besked -------- 08.05.2024 08.58, Igor Augustynski skrev:

Still relevant. Setting a min or max does not change the control value, so the valueChanges Observable on the control should not emit a new value.

— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you commented.Message ID: @.***>

xbisa avatar May 08 '24 07:05 xbisa

Because filter() is a poor workaround at best, not a fix, and it does not work in every possible scenario. The distinctUntilChanged operator would be better, but a first value to compare to (a) is not always available.

igoraugustynski avatar May 08 '24 07:05 igoraugustynski