简体   繁体   中英

ExpressionChangedAfterItHasBeenCheckedError in ngIf?

I can't figure out what I'm missing here.

SharedServiceA:

export class SharedServiceA {
    somethingWasUpdated = new Subject();

    updateSomething(value) {
        this.somethingWasUpdated.next(value);
    }
}

AnotherService:

export class AnotherService {
    doSomething() {
        this.sharedServiceA.updateSomething(true);
    }
}

component-a.component.ts

export class ComponentA {
    list = [];
    isShowList = false;

    ngOnInit() {
        this.sharedServiceA.somethingWasUpdated
            .pipe(takeUntil(this.destroyed))
            .subscribe(
                data => {
                    if (data) {
                        this.fetchData(); // Get data from another service, then populate list
                    }
                }
            );
    }
    
    fetchData() {
        // Get data from another service
        if (dataFound) {
            this.list = dataFound;
            this.isShowList = true;
        } else {
            this.isShowList = false;
        }
    }
}

component-a.component.html

<div *ngIf="!isShowList"> <!-- This is where ExpressionChangedAfterItHasBeenCheckedError points to: Previous value: 'ngIf: true'. Current value: 'ngIf: false' -->
    List empty
</div>
<div *ngIf="isShowList">
    Print something here
</div>

component-b.component.html

export class ComponentB {
    ngOnInit() {
        this.sharedServiceA.somethingWasUpdated
            .pipe(takeUntil(this.destroyed))
            .subscribe(
                data => {
                    if (data) {
                        // Get data from another service
                    }
                }
            );

        this.anotherService.doSomething(); // If I place this inside a setTimeout, I don't get the ExpressionChangedAfterItHasBeenCheckedError
    }
}

This is the scenario:

  1. Click on a button > ComponentA gets created inside a tab

  2. Click on another button > ComponentB gets created inside another tab (basically side by side with ComponentA ) > ComponentA.fetchData() > ExpressionChangedAfterItHasBeenCheckedError

Why would I get an ExpressionChangedAfterItHasBeenCheckedError in ComponentA after list was populated and isShowList was set to true and why don't I get the error if I place this.anotherService.doSomething(); inside a setTimeout ?

How is this code violating the unidirectional data flow? Even after reading several articles, I'm still confused in this particular case.

Quick point, ExpressionChangedAfterItHasBeenChecked errors only visible in dev mode. Do not show in production mode.

In your component use changeDectectorRef like below:

    import { ChangeDetectorRef} from "@angular/core";

    constructor(private ref: ChangeDetectorRef){}

  fetchData() {
        // Get data from another service
        if (dataFound) {
            this.list = dataFound;
            this.isShowList = true;
        } else {
            this.isShowList = false;
        }
      this.ref.detectChanges();
    }

2nd method

If above doesnt work for you then use it in AfterViewChecked life cycle hooks.

ngAfterViewChecked() {
     this.ref.detectChanges();
}

Hope this helps you!!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM