patchValue with { emitEvent: false } triggers valueChanges on Angular 4 formgroup
Asked Answered
A

6

64

I have a formbuilder group and am listening for changes with valueChanges and triggering a save function followed by refresh function on the form:

 this.ticketForm.valueChanges.debounceTime(1000).distinctUntilChanged()
 .subscribe(data => {
   this.saveTicket();
   this.refreshTicket();
 })

I am then reloading the form and repatching the data to form fields (and elsewhere on the page, particularly a change log) with patchValue, e.g.:

    this.ticketForm.patchValue(ticket, { emitEvent: false });

however, this causes an infinite loop of saves of the form despite emitEvent : false.

Is this an Angular 4/Ionic 3 bug or a misunderstanding on my part?

Atchison answered 21/7, 2017 at 15:11 Comment(14)
what do you expect from { emitEvent: false }?Satellite
That the patching of the value does not emit a change event that would be detected by valueChanges...Atchison
can you create a plunker? patchValue shouldn't trigger value changes on the form even without emitEvent: falseSatellite
Same here, did you find answer for it?Renaldo
Me too, did you find an answer?Hartz
I did not. I worked around it by avoiding using patchValueAtchison
With angular 5 It didn't fire the event with patchValue(value, {emitEvent: false})Desex
I'm using Angular 6 and an ngModelChange event is still firing.Vair
I'm using Angular 6 as well, and it's still firing with emitEvent: false... This isn't happening for everyone?Soledadsolely
Same misbehaviour here; event fires despite {emitEvent: False}. Angular 6.Chronologist
Same for me on Angular 7.Reahard
I had the same issue, I realised that it was because I was using a customFormControl and my custom form control was not taking emitEvent: false into consideration on initialisationMincemeat
There's a bug open on @Mincemeat issue. Thank you for mentioning this, I would have been stuck quite a while trying to suss out what was going wrong.Atone
same issue with ng 10 and with setValueLegra
V
51

Try adding onlySelf: true along with the emitEvent: false in this way:

this.ticketForm.patchValue(ticket, {emitEvent: false, onlySelf: true});
Vanhoose answered 24/11, 2018 at 17:35 Comment(6)
not sure if this worked for the OP, but didn't work for meJana
This worked for me. modify as well like this, this.ticketform.updateValueAndValidity({emitEvent: false, onlySelf: true})Octodecimo
This may be a bug. From the documentation, it says that the default for onlySelf should be true and this should have no effect. In any case, the behavior here does not match the expected behavior in the documentation.Butchery
I was using setValue with only emitEvent and it worked for me, Thanks!Prudential
I tried the solution above and it works for me aswell. Nevertheless, the Pradeep comment let me perplex.. I hope there are no side effects.Productive
It doesn't work for me in 13.0.2. It does work when enabling a control that was previously disabled. this.formGroup.controls['samplingTime'].enable({emitEvent: false}). But it does not work with setValue/reset this.formGroup.get('samplingTime').reset(new Date(), {emitEvent: false, onlySelf: true}); I am using Subscribe().Quicktempered
R
12

Can't comment because of rep, so I will post it as an answer to @Craig Wayne.

emitEvent:false works only if you are listening to value changes on the form control with:

this.form.valueChanges.controlName.subscribe(val => doSomething(val));

if you are binding to model changes on the element event is emitted regardless:

<input (ngModelChange)="doSomething($event)"/>
Retributive answered 12/12, 2020 at 13:42 Comment(0)
S
8

While working with Angular 9.1.13 I had been facing the same problem. Tried to use the FormControl.setValue, and FormGroup.patchValue APIs, using also the suggested params {emitEvent: false, onlySelf: true} in all possible combinations. The valueChanges observable is was still being triggered.

The only thing that worked for me eventually was :

myForm.disable();
myForm.patchValue({myControl: ''}, {onlySelf: true, emitEvent: false});
myForm.enable();
Slur answered 6/4, 2021 at 11:58 Comment(5)
My project is on Angular 8.3.21 and this is the only answer that worked for me. Thanks @SlurMustache
My project is on Angular 13, and even this did not work.Tham
@VictorZakharov as a last resort I would try to wrap the patchValue and/or the enable calls in a setTimeout(...). Not pretty but who knows...Slur
I just created my own framework/library around the standard valueChanges and rxjs, which can set a boolean variable, which changes the behavior accordingly.Tham
@VictorZakharov Open source it please!Touched
A
1

Why use a patchValue whenever a value changes instead of setting it once onInit?

Personally, I had this issue in a different context in building an option between two required FormControl's

I had a field clearing out another field (as designed, only one should be filled out), but then the subscribe triggered the original to clear. emitEvent:false didn't help because I needed my validators to run on an update. Adding if(value) helped it avoid cascade patching. See below:

this.formGroup.controls.item1.valueChanges.subscribe(value => {
   if(value){
     this.formGroup.patchValue({
       'item2':null
     })
   }
})

this.formGroup.controls.item2.valueChanges.subscribe(value => {
   if(value){
     this.formGroup.patchValue({
       'item1':null
     })
   }
})

Note: For simplicity sake, I didn't include the .pipe(takeUnitl(this.destroy$)). If you don't include this, it'll have a memory leak

Airman answered 5/7, 2021 at 21:42 Comment(1)
I recommend against rhetoric questions in answers. They risk being misunderstood as not an answer at all. You are trying to answer the question at the top of this page, aren't you? Otherwise please delete this post.Unheard
B
0

None of the answers worked for me, I had to do it manually:

First define a boolean variable in the class:

private dontAllowChangeEventFromForm = false;

Then i defined the following function, using rxjs pipe with filter

private getControlValueChangesWithRestrictions(control: AbstractControl): Observable<any> {
  return control.valueChanges.pipe(
    filter(_ => !this.dontAllowChangeEventFromForm)
  );
}

Then to listen to change use

this.getControlValueChangesWithRestrictions(this.form).subscribe()

Now whenever I want to silently update the form I do

this.dontAllowChangeEventFromForm = true;
this.form.patchValue(/*patch value*/)
this.dontAllowChangeEventFromForm = false;
Boeschen answered 2/8, 2023 at 6:3 Comment(0)
C
-1

As a workaround, i add skip to rxjs pipe

this.form.valueChanges
    .pipe(skip(1)).subscribe();
Curtis answered 9/12, 2019 at 6:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.