Angular 4 - “Expression has changed after it was checked” error while using NG-IF

后端 未结 6 1558
天命终不由人
天命终不由人 2020-12-14 21:05

I setup a service to keep track of logged in users. That service returns an Observable and all components that subscribe to it are notified (so

6条回答
  •  清歌不尽
    2020-12-14 21:22

    To understand the error, read:

    • Everything you need to know about the ExpressionChangedAfterItHasBeenCheckedError error

    You case falls under the Synchronous event broadcasting category:

    This pattern is illustrated by this plunker. The application is designed to have a child component emitting an event and a parent component listening to this event. The event causes some of the parent properties to be updated. And these properties are used as input binding for the child component. This is also an indirect parent property update.

    In your case the parent component property that is updated is user and this property is used as input binding to *ngIf="user". The problem is that you're triggering an event this._authService.sendMessage(checkStatus) as part of change detection cycle because you're doing it from lifecycle hook.

    As explained in the article you have two general approaches to working around this error:

    • Asynchronous update - this allows triggering an event outside of change detection process
    • Forcing change detection - this adds additional change detection run between the current run and the verification stage

    First you have to answer the question if there's any need to trigger the even from the lifecycle hook. If you have all the information you need for the even in the component constructor I don't think that's the bad option. See The essential difference between Constructor and ngOnInit in Angular for more details.

    In your case I would probably go with either asynchronous event triggering instead of manual change detection to avoid redundant change detection cycles:

    ngOnInit() {
      const checkStatus = this._authService.checkUserStatus();
      Promise.resolve(null).then(() => this._authService.sendMessage(checkStatus););
    }
    

    or with asynchronous event processing inside the AppComponent:

    ngAfterViewInit(){
        this.subscription = this._authService.getMessage().subscribe(Promise.resolve(null).then((value) => this.user = message));
    

    The approach I've shown above is used by ngModel in the implementation.

    But I'm also wondering how come this._authService.checkUserStatus() is synchronous?

提交回复
热议问题