Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Child ControlValueAccessor Component with formgroup - expression has changed after it was checked

Tags:

angular

on loading of my parent component, i am updating the form of that (parent) component by using patchValue.

on of that form components i my child ControlValueAccessor component that also has a formgroup. therefore, on my writeValue function i am updating the child component regarding the value that passed from the parent component patchValue.

my writeValue function looks like that:

    writeValue(value: CountryAndCity): void {
    if (value != null && value.country && value.city) {
      this.isDefaultValueDefined = true;
      this.form.patchValue({country: value.country});
      this.form.patchValue({city: value.city});
      **this.cdRef.detectChanges();**
    }
  }

As you can see, i had to use detectChanges() as the last line of the above function because without it i am getting the error:

ParentComponent.html:1 ERROR Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'ng-pristine: true'. Current value: 'ng-pristine: false'.

i think i understand why is that. Angular start the check of the parent component, then, start to check the child component but then, on the child component the child component, on the writeValue function changing the parent component form state.

i feel uncomfortable with the use of detectChanges(). is there a way to do something else? is it a must when using parent and child components that each of them has formGroup and the child component is one of the parent formgroup formControl?

like image 660
Omtechguy Avatar asked Feb 22 '18 09:02

Omtechguy


1 Answers

I don't think, that this is happening because of your write function but rather that something in your form is emitting values right after the child has been created, but it is hard to tell without seeing more of your code.

I had the same problem so what I did to prevent this error without manually triggering change detection was to decouple the value propagation to the parent from the current change detection cycle.

An easy way to achieve this is to yield in the value upstream like

this.form
  .valueChanges
  .pipe(
    delay(0)
  )
  .subscribe(it => {
    this.propagateChange(...)
  })

I do not know if this is the best approach but for me it works.

BTW: I would also recommend using {emitEvent: false} as patch options, which prevents the child from firing the event in the write function. This would solve your problem if your assumption about the source of the error is true, but wouldn't if my assumption was true.

like image 192
Tobi Avatar answered Oct 21 '22 16:10

Tobi