Expression ___ has changed after it was checked

后端 未结 17 1873
太阳男子
太阳男子 2020-11-22 05:53

Why is the component in this simple plunk

@Component({
  selector: \'my-app\',
  template: `
I\'m {{message}}
`, }) export class App {
相关标签:
17条回答
  • 2020-11-22 06:25

    First, note that this exception will only be thrown when you're running your app in dev mode (which is the case by default as of beta-0): If you call enableProdMode() when bootstrapping the app, it won't get thrown (see updated plunk).

    Second, don't do that because this exception is being thrown for good reason: In short, when in dev mode, every round of change detection is followed immediately by a second round that verifies no bindings have changed since the end of the first, as this would indicate that changes are being caused by change detection itself.

    In your plunk, the binding {{message}} is changed by your call to setMessage(), which happens in the ngAfterViewInit hook, which occurs as a part of the initial change detection turn. That in itself isn't problematic though - the problem is that setMessage() changes the binding but does not trigger a new round of change detection, meaning that this change won't be detected until some future round of change detection is triggered somewhere else.

    The takeaway: Anything that changes a binding needs to trigger a round of change detection when it does.

    Update in response to all the requests for an example of how to do that: @Tycho's solution works, as do the three methods in the answer @MarkRajcok pointed out. But frankly, they all feel ugly and wrong to me, like the sort of hacks we got used to leaning on in ng1.

    To be sure, there are occasional circumstances where these hacks are appropriate, but if you're using them on anything more than a very occasional basis, it's a sign that you're fighting the framework rather than fully embracing its reactive nature.

    IMHO, a more idiomatic, "Angular2 way" of approaching this is something along the lines of: (plunk)

    @Component({
      selector: 'my-app',
      template: `<div>I'm {{message | async}} </div>`
    })
    export class App {
      message:Subject<string> = new BehaviorSubject('loading :(');
    
      ngAfterViewInit() {
        this.message.next('all done loading :)')
      }
    }
    
    0 讨论(0)
  • 2020-11-22 06:25

    It throw an error because your code get updated when ngAfterViewInit() is called. Mean your initial value got changed when ngAfterViewInit take place, If you call that in ngAfterContentInit() then it will not throw an error.

    ngAfterContentInit() {
        this.updateMessage();
    }
    
    0 讨论(0)
  • 2020-11-22 06:30

    Can't you use ngOnInit because you just changing the member variable message?

    If you want to access a reference to a child component @ViewChild(ChildComponent), you indeed need to wait for it with ngAfterViewInit.

    A dirty fix is to call the updateMessage() in the next event loop with e.g. setTimeout.

    ngAfterViewInit() {
      setTimeout(() => {
        this.updateMessage();
      }, 1);
    }
    
    0 讨论(0)
  • 2020-11-22 06:31

    You just have to update your message in the right lifecycle hook, in this case is ngAfterContentChecked instead of ngAfterViewInit, because in ngAfterViewInit a check for the variable message has been started but is not yet ended.

    see: https://angular.io/docs/ts/latest/guide/lifecycle-hooks.html#!#afterview

    so the code will be just:

    import { Component } from 'angular2/core'
    
    @Component({
      selector: 'my-app',
      template: `<div>I'm {{message}} </div>`,
    })
    export class App {
      message: string = 'loading :(';
    
      ngAfterContentChecked() {
         this.message = 'all done loading :)'
      }      
    }
    

    see the working demo on Plunker.

    0 讨论(0)
  • 2020-11-22 06:32

    You can also put your call to updateMessage() in the ngOnInt()-Method, at least it works for me

    ngOnInit() {
        this.updateMessage();
    }
    

    In RC1 this does not trigger the exception

    0 讨论(0)
提交回复
热议问题