为什么我在控制台中收到以下警告?一切似乎都按预期进行,但是Angular抱怨。这个问题有什么解决方案?
StackBlitz是here
我知道一种可能的解决方案是通过父子通信而不是使用服务来通信事件,但这不是我的选择,因为这是较大代码库中问题的隔离。
错误消息
ERROR Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'ngIf: false'. Current value: 'ngIf: true'.
at viewDebugError (core.js:20439)
at expressionChangedAfterItHasBeenCheckedError (core.js:20427)
at checkBindingNoChanges (core.js:20529)
at checkNoChangesNodeInline (core.js:23400)
at checkNoChangesNode (core.js:23389)
at debugCheckNoChangesNode (core.js:23993)
at debugCheckDirectivesFn (core.js:23921)
at Object.eval [as updateDirectives] (AppComponent.html:6)
at Object.debugUpdateDirectives [as updateDirectives] (core.js:23910)
at checkNoChangesView (core.js:23288)
app.component.html
<div style="text-align:center">
<h1>
Welcome to {{ title }}!
</h1>
<h1 *ngIf="mainSectionContent?.buttontext?.length > 0">
Welcome to {{ title }}!
</h1>
<app-employee></app-employee>
</div>
AppComponent
export class AppComponent implements OnInit {
title = 'expression-changed';
mainSectionContent:MainSectionContent;
contentAnnounce$:Observable<MainSectionContent>;
constructor(private mainContentService:MaincontentService) { }
ngOnInit(): void {
this.contentAnnounce$ = this.mainContentService.contentAnnounce$;
this.contentAnnounce$.subscribe(mainSectionContent =>
{
this.mainSectionContent = mainSectionContent
}
);
}
}
EmployeeComponent
export class EmployeeComponent implements OnInit {
constructor(private mainSectionContentService:MaincontentService) { }
ngOnInit() {
this.mainSectionContentService.announceContent({
mainheading:'Employee Manger',
mainsubheading:'To manage PrivilegeManager Employees',
sectionheading:'Employee List',
buttontext:'Create Employee'
});
}
}
MaincontentService
@Injectable({
providedIn: 'root'
})
export class MaincontentService {
private contentAnnounce = new Subject<MainSectionContent>();
contentAnnounce$ = this.contentAnnounce.asObservable();
constructor() { }
announceContent(content:MainSectionContent){
this.contentAnnounce.next(content);
}
}
答案 0 :(得分:2)
我曾经遇到过同样的问题,但是它以有角度的本机方式工作,您可以按照以下代码使用angular / core类的ChangeDetectorRef:
constructor(private cdf: ChangeDetectorRef){}
在您的情况下,在控制器中收到数据后添加以下行:
this.mainSectionContent = mainSectionContent
this.cdf.detectChanges();
这是在要求角度服务重新检查DOM上的更改。
答案 1 :(得分:1)
情况是已经检查*ngIf="mainSectionContent?.buttontext?.length > 0"
之后调用了EmployeeComponent的ngOnInit。
首先检查父组件,然后转到子EmployeeComponent
,该子组件更改值,该值已用于在同一事件循环迭代中呈现父组件。
这看起来像是骇客,但您必须在第一个循环通过后调用announceContent。您可以在第一个事件循环结束后尝试调用它:
ngOnInit() {
setTimeout(() => {
this.mainSectionContentService.announceContent({
mainheading:'Employee Manger',
mainsubheading:'To manage PrivilegeManager Employees',
sectionheading:'Employee List',
buttontext:'Create Employee'
});
},
0);
}
答案 2 :(得分:0)
好吧,这个 ExpressionChangedAfterItHaHasBeenCheckedError:错误已经持续了一段时间,看来唯一,最好的解决方法是使用:
setTimeout(() => {...changes...});
---or---
Promise.resolve(null).then(() => {...changes...});
但是要存档必须在每个组件或区域上实现的存档,您想要进行这些更改。那可能是一个真正的麻烦。
因此,我认为最好的方法是将类display: none
绑定到要隐藏的HtmlElement上。
.d-none {
display: none
}
<div style="text-align:center">
<h1>
Welcome to {{ title }}!
</h1>
<h1 [class.d-none]="mainSectionContent?.buttontext?.length > 0">
Welcome to {{ title }}!
</h1>
<app-employee></app-employee>
</div>
ngOnInit() {
this.mainSectionContentService.announceContent({
mainheading:'Employee Manger',
mainsubheading:'To manage PrivilegeManager Employees',
sectionheading:'Employee List',
buttontext:'Create Employee'
});
}