angular / components

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

bug(MatDatePicker): change events emitted despite using emitEvents false #20218

Open rraziel opened 4 years ago

rraziel commented 4 years ago

Reproduction

https://stackblitz.com/edit/components-issue-xay9ty?file=src%2Fapp%2Fexample-component.ts

  1. Click the "emitEvent: false" button

Expected Behavior

valueChanges should not emit values when setting a value with emitEvent: false

This works correctly for "normal" input components, but not when attaching a date picker.

The reproduction includes a text input and a select for comparison.

Actual Behavior

Using setValue or patchValue with emitEvent set to false has the valueChanges observable emit changes.

Environment

jelbourn commented 4 years ago

Marking as "needs discussion" since we should look into how broadly this option should be respected

rraziel commented 4 years ago

Just a extra note on the why:

  1. valueChanges subscription that dispatches to an ngrx store
  2. ngrx selector from the store that does a set/patchValue with emitEvent false

This is used as a simple mechanism to keep the state in ngrx, but with the emitEvent ignored it becomes an infinite loop.

Brutusn commented 4 years ago

I encountered this bug aswell.

I have a formGroup (attached to a <mat-date-range-*> inside the template):

readonly myRange = new FormGroup({ start: new FormControl({ value: null, disabled: true }), end: new FormControl({ value: null, disabled: true }), });

I do listnen to the value changes, with nothing special, just to console log the value.

this.myRange.valueChanges.subscribe(console.log);

Later in my code I patch the value with emit false.

this.myRange.patchValue({ start: new Date(2020, 9, 5), end: new Date(2020, 9, 10) }, { emitEvent: false });

The value is correctly set, but I don't expect the console.log to show anything.

Edit: added a stack blitz to show the issue: https://stackblitz.com/edit/angular-ivy-hgtnqf?file=src%2Fapp%2Fapp.component.ts

MikeDabrowski commented 2 years ago

Throwing my few cents in here as well: https://stackblitz.com/edit/angular-fgkwso?file=src/app/datepicker-harness-example.spec.ts

Im synchronising the form state with the ngrx store and relying on the 'emitEvent' flag quite heavily.

Edit: and this bug propagated to Angular@12 :)

Edit2: A little investigation:

when calling form.reset({...values}, {emitEvent: false}), I've pinpointed the place where options get lost. It happens in matDatePicker but the place where the option should be passed is I think in forms. Take a look at this screen:

image

The _forEachChild calls are coming directly from reset() method. Then it goes down to formControl's reset where the value is set. SetValue is called with proper arguments, emitEvent: false, but it invokes _onChange functions and omits the options when passing arguments. image

Then we have onChange which calls MatDatepickerInputBase.writeValue and here no options are even available.

Maybe someone from angular team can reflect on that.

Edit 3: Ugly workaround that seems to work is to filter based on flag set before reset an cleared after (cleared possibly with settimeout)

vgb1993 commented 2 years ago

Same problem here, I run into unwanted valueChanges notifications when doing either FormGroup.PatchValue and FormGroup.SetValue with emitEvent: false. Looks like the controls are the ones firing the evnts.

Shouldn't this option be cascaded? What's the reason otherwise?

vgb1993 commented 2 years ago

Edit 3: Ugly workaround that seems to work is to filter based on flag set before reset an cleared after (cleared possibly with settimeout)

What if we disconect the FormCobntrols from the FormGroup, then update and then reconect?

YugasVasyl commented 2 years ago

The same issue, fixed it using skipWhile, but it's a pain

UshakovMaksym commented 2 years ago

The problem is in interface, we are setting emitEvent option, but FormControl component check old option name emitViewModelChange.

weilinzung commented 2 years ago

Same issue here with ng14, the emitEvent: false doesn't work properly when it is with mat-date-range-input.

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

jziggas commented 1 year ago
image
jambudipa commented 10 months ago

Yeah, still an issue. Not sure if setting a flag is guaranteed to work, sync/async, who knows.

MIZUDINOV commented 8 months ago

Angular 13 and same problem

dan-consignly commented 7 months ago

It's 2024, we're using Angular 17, and this issue is still occurring.

mohamed-badaoui commented 3 months ago

any update on this issue ?

Pipeze commented 2 months ago

The workaround that got me through this in the context of syncing an ngrx store with my form is managing a subscription and unsubscribe/resubscribe whenever I want to patch my form.

syncFormToStoreSub?: Subscription;
syncFormToStore$ = this.form.valueChanges.pipe(
    takeUntil(this.onDestroy$),
    tap(value => {
        // Update store
    })
)

ngOnInit() {
    this.syncFormToStoreSub = this.syncFormToStore$.subscribe();

     this.store
          .select(selectMyStoreDates)
          .pipe(
               takeUntil(this.onDestroy$),
               tap(myStoreDates => {
                    if (this.syncFormToStoreSub) {
                         this.syncFormToStoreSub.unsubscribe();
                    }
                    this.form.patchValue(...);
                    this.syncFormToStoreSub = this.syncFormToStore$.subscribe();
               })
          ).subscribe();
}
Iquis commented 3 weeks ago

I got the same exact use case. I have a range value in my ngrx store so I need to set new values in the MatDateRangeInput when it changes. I used setValue (same problem with patchValue) with EmitEvent false. But no matter what, it still triggers valueChanges on the formGroup

https://stackblitz.com/edit/stackblitz-starters-yga1yz?file=src%2Ftest%2Ftest.component.ts