dre*_*ore 241 typescript angular
为什么这个组件在这个简单的插件中
@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 :)'
}
}
Run Code Online (Sandbox Code Playgroud)
投掷:
例外:App @ 0:5'中的表达式'我'{{message}}在检查后发生了变化.上一个值:'我正在加载:('.当前值:'我已经完成了加载:)'在[我是{{message}}在App @ 0:5中]
什么时候我正在做的是在我的视图启动时更新一个简单的绑定?
Tyc*_*cho 246
正如drewmoore所述,在这种情况下,正确的解决方案是手动触发当前组件的变化检测.这是使用对象的detectChanges()方法ChangeDetectorRef(从中导入angular2/core)或其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();
}
}
Run Code Online (Sandbox Code Playgroud)
这里同时Plunkers展示ngOnInit,setTimeout的,并且enableProdMode以防万一的方法.
dre*_*ore 151
首先,请注意,只有当您以开发模式运行应用程序时才会抛出此异常(默认情况下属于beta-0):如果您enableProdMode()在引导应用程序时调用它,则不会抛出它(请参阅更新了plunk).
其次,不要这样做是因为这个例外被抛出是有充分理由的:简而言之,当处于开发模式时,每一轮变更检测都会立即进行第二轮检查,以确认自第一轮结束后没有任何绑定发生变化,因为这表明变化是由变化检测本身引起的.
在你的插件中,绑定{{message}}会被你的调用改变setMessage(),这发生在ngAfterViewInit钩子中,这是初始变化检测转弯的一部分.这本身并不成问题 - 问题在于setMessage()更改绑定但不会触发新一轮的更改检测,这意味着直到某个未来的一轮更改检测在其他地方触发时才会检测到此更改.
要点:任何改变绑定的东西都需要触发一轮变化检测.
更新以响应所有请求以获取如何执行此操作的示例:@Tycho 的解决方案正常工作,@ MarkRajcok指出的答案中的三种方法也是如此.但坦率地说,他们都觉得我很难看,就像我们习惯于在ng1中依赖的那种黑客一样.
可以肯定的是,偶尔存在这些黑客攻击的情况,但是如果你在非常偶然的基础上使用它们,那就表明你正在与框架作斗争,而不是完全接受它的反应性质.
恕我直言,一个更惯用的,"Angular2方式"接近这一点是这样的:( 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 :)')
}
}
Run Code Online (Sandbox Code Playgroud)
Bir*_*chi 42
我通过从angular core添加ChangeDetectionStrategy来解决这个问题.
import { Component, ChangeDetectionStrategy } from '@angular/core';
@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
selector: 'page1',
templateUrl: 'page1.html',
})
Run Code Online (Sandbox Code Playgroud)
Jo *_*VdB 34
你不能使用,ngOnInit因为你只是改变成员变量message?
如果要访问子组件的引用@ViewChild(ChildComponent),确实需要等待它ngAfterViewInit.
一个脏修复是updateMessage()使用例如setTimeout 调用下一个事件循环.
ngAfterViewInit() {
setTimeout(() => {
this.updateMessage();
}, 1);
}
Run Code Online (Sandbox Code Playgroud)
Jas*_*mar 34
ngAfterViewChecked()为我工作:
import { Component, ChangeDetectorRef } from '@angular/core'; //import ChangeDetectorRef
constructor(private cdr: ChangeDetectorRef) { }
ngAfterViewChecked(){
//your code to update the model
this.cdr.detectChanges();
}
Run Code Online (Sandbox Code Playgroud)
Sha*_*asi 29
我从 AfterViewInit 切换到 AfterContentChecked 并且它对我有用。
这是过程
在构造函数中添加依赖项:
constructor (private cdr: ChangeDetectorRef) {}
并在此处使用已实现的方法代码调用您的登录名:
ngAfterContentChecked() {
this.cdr.detectChanges();
// call or add here your code
}
Run Code Online (Sandbox Code Playgroud)
Max*_*kyi 22
文章关于ExpressionChangedAfterItHasBeenCheckedError错误需要了解的所有内容都会详细解释行为.
您设置的问题ngAfterViewInit是在更改检测处理DOM更新后执行生命周期钩子.并且您正在有效地更改此挂钩中模板中使用的属性,这意味着需要重新呈现DOM:
ngAfterViewInit() {
this.message = 'all done loading :)'; // needs to be rendered the DOM
}
Run Code Online (Sandbox Code Playgroud)
这将需要另一个更改检测周期,而Angular by design只运行一个摘要周期.
你基本上有两个选择如何解决它:
异步更新属性或者使用setTimeout,Promise.then或在模板中引用异步观察到
在DOM更新之前在钩子中执行属性更新 - ngOnInit,ngDoCheck,ngAfterContentInit,ngAfterContentChecked.
sha*_*ain 14
出现此错误是因为现有值在初始化后立即更新。因此,如果您在 DOM 中呈现现有值后更新新值,那么它会正常工作。就像这篇文章中提到的Angular Debugging “Expression has changed after it was checked”
例如你可以使用
ngOnInit() {
setTimeout(() => {
//code for your new value.
});
Run Code Online (Sandbox Code Playgroud)
}
或者
ngAfterViewInit() {
this.paginator.page
.pipe(
startWith(null),
delay(0),
tap(() => this.dataSource.loadLessons(...))
).subscribe();
}
Run Code Online (Sandbox Code Playgroud)
正如你所看到的,我没有在 setTimeout 方法中提到时间。因为它是浏览器提供的 API,而不是 JavaScript API,所以这将在浏览器堆栈中单独运行,并等待调用堆栈项完成。
Philip Roberts 在 Youtube 视频之一中解释了浏览器 API 如何激发概念(黑客是什么事件循环?)。
为此,我已经尝试了以上答案,但许多版本在Angular的最新版本(6或更高版本)中均不起作用
我正在使用Material控件,该控件在完成第一次绑定后需要进行更改。
export class AbcClass implements OnInit, AfterContentChecked{
constructor(private ref: ChangeDetectorRef) {}
ngOnInit(){
// your tasks
}
ngAfterViewInit() {
this.ref.detectChanges();
}
}
Run Code Online (Sandbox Code Playgroud)
因此,请添加我的答案,这有助于解决某些特定问题。
您只需要在正确的生命周期钩子中更新您的消息,在这种情况下,ngAfterContentChecked而不是ngAfterViewInit,因为在ngAfterViewInit 中,已经启动了对变量消息的检查但尚未结束.
请参阅:https: //angular.io/docs/ts/latest/guide/lifecycle-hooks.html#!#afterview
所以代码将是:
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 :)'
}
}
Run Code Online (Sandbox Code Playgroud)
看看Plunker 的工作演示.
简单:首先在组件构造中分离/删除更改检测,然后detectChanges()在ngAfterViewInit()方法中启用
constructor(private cdr: ChangeDetectorRef) {
this.cdr.detach() // detach/remove the change detection here in constructor
}
ngAfterViewInit(): void {
// do load objects or other logics here
// at the end of this method, call detectChanges() method.
this.cdr.detectChanges(); // enable detectChanges here and you're done.
}
Run Code Online (Sandbox Code Playgroud)
您还可以在 ngOnInt()-Method 中调用 updateMessage() ,至少它对我有用
ngOnInit() {
this.updateMessage();
}
Run Code Online (Sandbox Code Playgroud)
在 RC1 中,这不会触发异常
| 归档时间: |
|
| 查看次数: |
155352 次 |
| 最近记录: |