I'm trying to act on a parent component based on a child output, but i'm getting
Expression has changed after it was checked. Previous value: 'ngIf: [object Object]'. Current value: 'ngIf: true'.
Here is my code:
Parent Component html
<div *ngIf="hasErrors">!</div>
<app-error [valuesForErrors]="..." (hasErrors)="setHasErrors($event)"></app-error>
Parent Component ts (section)
export class InputComponent implements OnInit {
hasErrors = false;
...
setHasErrors(hasErrors) {
this.hasErrors = hasErrors;
}
I've seen some solutions with Subject and Observable from rxjs, but they didn't work on my project :/
Edit
A friend helped gave me another solution, just make the emitter asynchronous with a true on the declaration:
Child Component ts
export class ErrorComponent implements OnInit, OnChanges {
@Input() valuesForErrors: any;
@Output() hasErrors: EventEmitter<boolean> = new EventEmitter<boolean>(true);
...
ngOnChanges(changes: SimpleChanges): void {
this.calculateErrors()
}
calculateErrors() {
let errors = ... some logic that returns a boolean;
this.hasErrors.emit(errors);
}
}
Have you ever wondered if the world is just out to get you?
Well, sometimes it's true. You've encountered one of the nastiest behaviours that angular throws.
Normally, like 95% of the time, ExpressionChangedAfterItHasBeenCheckedError is basically angular telling you that you don't understand the basics of lifecycle detection: ngOnChanges vs ngOnInit vs ngAfterViewInit. But occasionally it's because of the nesting and template hierarchy and the order checks are made in your template.
Take the following which throws the error:
<form [name]="formName"
[formGroup]="formGroup">
<div *ngIf="true">
<input formControlName="name"
required
placeholder="Please enter you name">
</div>
</form>
<div *ngIf="formGroup.valid">
Name is required.
</div>
The reason for the error being thrown is that change detection evaluates the *ngIf of the error div first before it evaluates the input's validity, as the input is one level lower in terms of template hierarchy.
A workaround is to bring the error div onto the same level as the input by adding just another <div *ngIf="true"></div> around it (as mentioned above).
Not all heros wear capes, some leave Github comments
Modify parent component like this:
import { ChangeDetectorRef } from '@angular/core';
constructor(private cd: ChangeDetectorRef) { }
setHasErrors(hasErrors) {
this.hasErrors = hasErrors;
this.cd.detectChanges();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With