I have a parent - child component with reactive forms. Child propagates changes to parent via ControlValueAccessor.
I need to pass initial value via the template with @Input annotated variable (in the real app I want to pass the initial value from ngFor hence the @Input).
I can't set the passed in initial value during formGroup creation in the child constructor because the @Input ed value is not available yet.
I also can't set it in ngOnInit for the same reason.
In afterViewInit I can do it, and it's working, BUT only if I wrap the patchValue call inside a setTimeout. Otherwise NG0100: Expression has changed after it was checked error is thrown:
ngAfterViewInit() {
console.log('ngAfterViewInit called');
// if I omit setTimeout then NG0100: ExpressionChangedAfterItHasBeenCheckedError
// is it OK for using setTimeout for this?
setTimeout(() => {
this.formGroup.patchValue({
firstName: this.initialFirstName,
});
}, 0);
}
Is it OK to use setTimeout to avoid the error, is it reliable? Is there a better solution?
The whole thing is here: https://stackblitz.com/edit/angular-ivy-rohjor?file=src/app/name-input/name-input.component.ts
It would have worked inside
ngOnInit, but the problem is that the change handler of your control value accessor is not yet registered. You can do it insideregisterOnChangehandler like this:This way, when your subscribe handler inside the
ngOnInitmethod is hit, thethis.onChangewill have the correct value (the one that was registered through the control value accessor).I recommend you to stop giving default values to these control value accessor handlers because this way, you will actually get more meaningful errors (like
Error: this.onChange is not a function) that should trigger this alarm for you and let you know that you try to use the handler before it was registered: