57

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?

larpo
  • 1,073
  • 1
  • 10
  • 18

6 Answers6

46

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

this.ticketForm.patchValue(ticket, {emitEvent: false, onlySelf: true});
סטנלי גרונן
  • 2,917
  • 23
  • 46
  • 68
Lakshay
  • 536
  • 5
  • 15
  • 30
    not sure if this worked for the OP, but didn't work for me – Craig Wayne Feb 06 '20 at 10:16
  • This worked for me. modify as well like this, `this.ticketform.updateValueAndValidity({emitEvent: false, onlySelf: true})` – Pradeep shyam Feb 04 '21 at 11:17
  • 3
    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. – Jared G Feb 17 '21 at 20:22
  • I was using setValue with only emitEvent and it worked for me, Thanks! – Khuram Niaz Oct 06 '21 at 22:00
  • 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. – mtnp Nov 30 '21 at 16:03
  • 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(). – Norbert Norbertson Apr 26 '23 at 11:39
9

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)"/>
5

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();
ktsangop
  • 1,013
  • 2
  • 16
  • 29
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

Ben Petersen
  • 471
  • 4
  • 15
  • 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. – Yunnosch Jul 05 '21 at 21:56
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;
LW001
  • 2,452
  • 6
  • 27
  • 36
Sean Meir
  • 21
  • 3
-1

As a workaround, i add skip to rxjs pipe

this.form.valueChanges
    .pipe(skip(1)).subscribe();
Wei Lun
  • 45
  • 2
  • 9