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

@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]

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


当前回答

我从AfterViewInit切换到AfterContentChecked,它为我工作。

流程如下

在构造函数中添加依赖项: 构造函数(私有cdr: ChangeDetectorRef) {} 在实现方法代码中调用你的登录: ngAfterContentChecked () { this.cdr.detectChanges (); //调用或添加您的代码 }

其他回答

只需将代码移动到要更改共享服务主题的组件的构造函数中

首先,请注意,这个异常只会在你以开发模式运行应用程序时被抛出(这是beta-0的默认情况):如果你在引导应用程序时调用enableProdMode(),它不会被抛出(参见updated plunk)。

其次,不要这样做,因为抛出这个异常是有充分理由的:简而言之,当处于开发模式时,每一轮更改检测之后都会立即进行第二轮,以验证自第一轮结束以来没有绑定发生更改,因为这将表明更改是由更改检测本身引起的。

在你的plunk中,绑定{{message}}是通过调用setMessage()来改变的,这发生在ngAfterViewInit钩子中,它作为初始变更检测回合的一部分发生。不过这本身并没有问题——问题是setMessage()改变了绑定,但不会触发新一轮的变更检测,这意味着直到在其他地方触发了未来的变更检测,才会检测到此更改。

结论:任何更改绑定的操作都需要触发一轮更改检测。

更新以回应所有关于如何做到这一点的例子的请求:@Tycho的解决方案是有效的,就像回答@MarkRajcok指出的三种方法一样。但坦率地说,我觉得他们都很丑陋,很错误,就像我们在ng1中习惯依赖的那种黑客一样。

可以肯定的是,在偶尔的情况下,这些hack是合适的,但如果您只是在非常偶然的基础上使用它们,这表明您正在与框架作斗争,而不是完全接受它的响应性。

恕我直言,更习惯的“Angular2方式”是这样的:(砰)

@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 :)')
  }
}

你不能用ngOnInit因为你只是改变了成员变量消息?

如果你想访问子组件@ViewChild(ChildComponent)的引用,你确实需要用ngAfterViewInit来等待它。

一个肮脏的修复方法是在下一个事件循环中调用updateMessage(),例如setTimeout。

ngAfterViewInit() {
  setTimeout(() => {
    this.updateMessage();
  }, 1);
}

我有几乎相同的案例,我有一系列的产品。我不得不让用户删除产品根据他们的选择。最后,如果数组中没有产品,那么我需要显示取消按钮而不是返回按钮,无需重新加载页面。

我通过检查ngAfterViewChecked()生命周期钩子中的空数组来完成。 这就是我是如何做到的,希望它有帮助:)

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

products: Product[];
someCondition: boolean;

constructor(private cdr: ChangeDetectorRef) {}

ngAfterViewChecked() {
  if(!this.someCondition) {
    this.emptyArray();
  }
}

emptyArray() {
    this.someCondition = this.products.length === 0 ? true : false;

    // run change detection explicitly
    this.cdr.detectChanges();
}

removeProduct(productId: number) {
    // your logic for removing product.
}

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

ngAfterContentInit() {
    this.updateMessage();
}