angular / components

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

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

Open gogakoreli opened 6 years ago

gogakoreli commented 6 years ago

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

Msimoneau commented 6 years ago

@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

gogakoreli commented 6 years ago

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

mmalerba commented 6 years ago

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

probert94 commented 4 years ago

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.

masoudtahmasebi93 commented 3 years ago

Any news on this? Is this issue fixed ?

Ajiharan commented 3 years ago

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; }

csvn commented 2 years ago

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

grsubin commented 1 year ago

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...
}
serg-mois-capital commented 1 year ago

Angular 16.2.0 - the issue is still relevant.

xbisa commented 1 year ago

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);
        },
      });
igoraugustynski commented 3 months ago

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.

xbisa commented 3 months ago

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: @.***>

igoraugustynski commented 3 months ago

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.

sh977218 commented 2 weeks ago

it would be really nice if reactive form control's value got set only when the calendar picker is closed, or the apply button is clicked.