为什么这个组件在这个简单的砰砰声中

@Component({
  selector: 'my-app',
  template: `<div>I'm {{message}} </div>`,
})
export class App {
  message:string = 'loading :(';

  ngAfterViewInit() {
    this.updateMessage();
  }

  updateMessage(){
    this.message = 'all done loading :)'
  }
}

扔:

例外:表达式'I'm {{message}} in App@0:5'在被检查后发生了变化。之前的值:'I'm loading:('。当前值:'I'm all done loading:)' in [I'm {{message}} in App@0:5]

当我所做的一切都是更新一个简单的绑定时,我的视图被启动?


当前回答

ngAfterViewChecked()为我工作:

import { Component, ChangeDetectorRef } from '@angular/core'; //import ChangeDetectorRef

constructor(private cdr: ChangeDetectorRef) { }
ngAfterViewChecked(){
   //your code to update the model
   this.cdr.detectChanges();
}

其他回答

不错的答案。然而,在我看来,当我使用: ChangeDetectorRef和AfterViewInit, Angular会进入一些额外的渲染周期,如果我的HTML代码设计得不是很小心,或者需要在TS代码中调用几个依赖于刷新的函数,我就会得到额外的视图渲染调用,因此会有额外的处理。

这里有一个我喜欢使用的解决方案,因为我不需要担心任何这些,它在编程上非常简单,并且不需要我或系统太多额外的东西。每当Angular给我带来“Expression has changed after it was checked”这种臭名昭著的错误时,我使用它都没有问题。

我有这个小的public/exported函数,它只是通过一个零延迟承诺传递我的值。这样做的目的是迫使JavaScript/JS进入另一个后台周期,从而将值更新分离到下一个处理周期,并-防止错误。(请注意,JS的周期与Angular HTML的视图呈现周期不同,处理强度更低)。

export async function delayValue(v: any, timeOutMs: number = 0): Promise<any> {
    return new Promise((resolve) => {
        setTimeout(() => {
          resolve(v);
        }, timeOutMs);
      });
}

现在,当我需要防止错误时,我简单地做:

this.myClassValue = await delayValue(newValue);

这只是一行代码。由于timeOutMs = 0的值,实际上没有明显的延迟。

下面是一个典型的场景:

myObservable$.subscribe(newValue  = {
    ...                // WHEN NEW VALUE ARRIVES FROM NOTIFIER(S)
    this.handleSubscribedValues(newValue);
    ...
});
                      // THIS MAY GIVE YOU THE ERROR !
private handleSubscribedValues(newValue) {
    this.myClassValue = newValue;
}
                      // SO, USE THIS INSTEAD TO AVOID THE ERROR
private async handleSubscribedValues(newValue) {
    this.myClassValue = await delayValue(newValue);
}

你也可以使用delayValue()函数和一些延迟/超时值,如果你需要等待一些事情发生,例如给用户几秒钟。

希望这对你们中的一些人有用。

正如drewmoore所说,在这种情况下,正确的解决方案是手动触发当前组件的变更检测。这是使用ChangeDetectorRef对象(从angular2/core导入)的detectChanges()方法完成的,或者它的markForCheck()方法,该方法也会更新任何父组件。相关例子:

import { Component, ChangeDetectorRef, AfterViewInit } from 'angular2/core'

@Component({
  selector: 'my-app',
  template: `<div>I'm {{message}} </div>`,
})
export class App implements AfterViewInit {
  message: string = 'loading :(';

  constructor(private cdr: ChangeDetectorRef) {}

  ngAfterViewInit() {
    this.message = 'all done loading :)'
    this.cdr.detectChanges();
  }

}

这里还有Plunkers演示了ngOnInit, setTimeout和enableProdMode方法以防万一。

它抛出一个错误,因为你的代码在ngAfterViewInit()被调用时被更新了。意思是当ngAfterViewInit发生时你的初始值被改变了,如果你在ngAfterContentInit()中调用它,那么它不会抛出一个错误。

ngAfterContentInit() {
    this.updateMessage();
}

我认为最简单的解决方法如下:

Make one implementation of assigning a value to some variable i.e. via function or setter. Create a class variable (static working: boolean) in the class where this function exists and every time you call the function, simply make it true whichever you like. Within the function, if the value of working is true, then simply return right away without doing anything. else, perform the task you want. Make sure to change this variable to false once the task is completed i.e. at the end of the line of codes or within the subscribe method when you are done assigning values!

在使用数据表时,我得到了类似的错误。当你在另一个*ngFor数据表中使用*ngFor时,会在它拦截角度变化周期时抛出这个错误。因此,不要在数据表内部使用数据表,而是使用一个常规的表或替换mf。带有数组名的数据。这很好。