Here is the stackblitz code,当使用service.ts
文件进行API调用时,我从子组件发出事件。
我的 child.comp.ts
import { Component, Output,EventEmitter } from '@angular/core';
import {Service} from './service';
@Component({
selector: 'child',
template: `Child data: {{data}}`
})
export class ChildComponent {
@Output() change = new EventEmitter();
data: string;
constructor(private svc: Service){}
ngOnInit(){
this.change.emit(true);
this.svc.getMsg()
.subscribe( data =>{
this.data = data;
this.change.emit(false);
})
}
}
我的 app.comp.ts
import { Component ,ChangeDetectorRef} from '@angular/core';
import {Service} from './service';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
name = 'Angular 6';
show= false;
constructor(svc: Service,private crd: ChangeDetectorRef){}
showData(event){
this.show = event;
// this.crd.detectChanges(); // this stops the error
}
}
正如您所看到的那样,通过让this.crd.detectChanges();
知道这是需要进行其他更改检测的部分,添加angular
可以阻止错误。
但是,I came across this answer on SO此错误基本上代表 BAD 设计。使用detectChanges()
似乎更像是一个修复,因为我必须明确地写它。
有人可以帮助我完成 GOOD 设计,我不必在生命周期中值更改的地方明确地detectChanges()
。
答案 0 :(得分:1)
所以,我调查了实现你所写内容的最佳方法。 I asked the same question to Max。我能得出的结论是
Angular遵循单向数据流as you can read over here
在您的情况下,您基本上是在CD中间更改show
的值。现在发生的事情是,当在DEV模式下第二次触发CD时,它会发现您使用EventEmitter
更改了来自子组件的父数据。这与 Angular的单向流相矛盾。在您的情况下可能的解决方案,
使用this.crd.detectChanges()
让角度知道显式您已经更改了值,因此角度将足以再次运行CD并且不会抛出任何值误差
或者,在子项本身中实现show
行为,而不是反对Parent的流程 - >子。
答案 1 :(得分:0)
当您以开发模式运行应用程序时(默认),更改检测器会遍历组件树两次:
那么问问自己是否真的需要从ngOnInit发出这个消息,这可能会导致其他地方的UI更改?如果你找不到更好的地方,尝试移动setTimeout()函数中的代码,这将确保在下一个事件循环周期调用此代码,当更改检测器完成其传递时