为什么我在 Angular 中得到 ExpressionChangedAfterItHasBeenCheckedError
Why do I get ExpressionChangedAfterItHasBeenCheckedError in Angular
我有以下 Angular 组件(针对问题进行了简化):
<md-sidenav-container fxFlex>
<div fxFlex class="app-content">
This is the content
</div>
<button *ngIf="newsbar.opened" type="button" (click)="closeBar(newsbar)">Close</button>
<button *ngIf="!newsbar.opened" type="button" (click)="openBar(newsbar)">Open</button>
<md-sidenav #newsbar mode="side" [opened]="showNewsBar()" align="end" class="app-news-bar">
<app-news-bar></app-news-bar>
</md-sidenav>
</md-sidenav-container>
下面是决定新闻栏是否打开的函数(根据window宽度)。
showNewsBar() {
const width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
if (width >= 1280) {
return true;
} else {
return false;
}
}
当 运行 应用程序时,一切都按预期工作。当 window 小于或变得小于 1280px 时,侧边栏关闭并显示 "Open" 按钮。当 window 大于或变得大于 1280px 时,侧边栏打开并显示 "Close" 按钮。但是,每当调整 window 的大小以触发函数 showNewsBar()
的更改时,我都会收到错误消息。
ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'true'. Current value: 'false'.
当我调整 window 的大小使其变大并打开新闻栏时,Previous value: 'false'. Current value: 'true'.
给我错误的那一行是按钮。出于某种原因,Angular 不喜欢我将 *ngIf 指令绑定到本地 MdSidenav 引用的 "opened" 属性.
同样,一切都按预期进行。功能没有问题。那么为什么会出现这个错误呢?有办法解决吗?
你会从这个 中找到这个错误的一些很好的原因。基本上, [opened]="showNewsBar()" 是导致此错误的原因。
引用@GünterZöchbauer 的 ,
Don't bind to methods or functions in the view, instead bind to fields
and update the fields in event handlers. If you must bind to methods,
ensure that they always return the same value instance as long as
there wasn't actually a change. Change detection will call these
methods a lot.
您可以将 opened
绑定到布尔变量,而不是使用 [opened]="showNewsBar()"
,并且 set/change 使用 ngOnInit
生命周期钩子和 window:resize
变量值] 事件。这是一个例子:
html:
<div fxFlex class="app-content">
This is the content
</div>
<button *ngIf="openFlag" type="button" (click)="sidenav.close(); openFlag = false">Close</button>
<button *ngIf="!openFlag" type="button" (click)="sidenav.open(); openFlag = true">Open</button>
<md-sidenav-container (window:resize)="onResize($event)" style="height: 91vh;background: #FFFFFF">
<md-sidenav #sidenav mode="side" [opened]="openFlag" align="end" style="background: orange">
Sidenav!
</md-sidenav>
</md-sidenav-container>
选项 1:(window:resize)
ts:
ngOnInit(){
this.onResize();
}
onResize(event) {
let width;
if(event != undefined){
width = event.target.innerWidth;
console.log(event.target.innerWidth);
}
else{
console.log(document.body.clientWidth);
width = document.body.clientWidth;
}
if (width >= 1280) {
this.openFlag = true;
}
else {
this.openFlag = false;
}
}
选项 2:弹性布局
我看到你有 fxFlex
表示你正在使用 flex-layout。 Flex-layout 附带 ObservableMedia
(doc)。您也可以使用它来设置 openFlag
.
的布尔值
此选项不需要视图中的 (window:resize)
事件。
ts:
import {MediaChange, ObservableMedia} from "@angular/flex-layout";
constructor(media: ObservableMedia) {
media.asObservable()
.subscribe((change: MediaChange) => {
if(change.mqAlias == 'lg' || change.mqAlias == 'xl'){
this.openFlag = true;
}
else{
this.openFlag = false;
}
});
}
我有以下 Angular 组件(针对问题进行了简化):
<md-sidenav-container fxFlex>
<div fxFlex class="app-content">
This is the content
</div>
<button *ngIf="newsbar.opened" type="button" (click)="closeBar(newsbar)">Close</button>
<button *ngIf="!newsbar.opened" type="button" (click)="openBar(newsbar)">Open</button>
<md-sidenav #newsbar mode="side" [opened]="showNewsBar()" align="end" class="app-news-bar">
<app-news-bar></app-news-bar>
</md-sidenav>
</md-sidenav-container>
下面是决定新闻栏是否打开的函数(根据window宽度)。
showNewsBar() {
const width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
if (width >= 1280) {
return true;
} else {
return false;
}
}
当 运行 应用程序时,一切都按预期工作。当 window 小于或变得小于 1280px 时,侧边栏关闭并显示 "Open" 按钮。当 window 大于或变得大于 1280px 时,侧边栏打开并显示 "Close" 按钮。但是,每当调整 window 的大小以触发函数 showNewsBar()
的更改时,我都会收到错误消息。
ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'true'. Current value: 'false'.
当我调整 window 的大小使其变大并打开新闻栏时,Previous value: 'false'. Current value: 'true'.
给我错误的那一行是按钮。出于某种原因,Angular 不喜欢我将 *ngIf 指令绑定到本地 MdSidenav 引用的 "opened" 属性.
同样,一切都按预期进行。功能没有问题。那么为什么会出现这个错误呢?有办法解决吗?
你会从这个
引用@GünterZöchbauer 的
Don't bind to methods or functions in the view, instead bind to fields and update the fields in event handlers. If you must bind to methods, ensure that they always return the same value instance as long as there wasn't actually a change. Change detection will call these methods a lot.
您可以将 opened
绑定到布尔变量,而不是使用 [opened]="showNewsBar()"
,并且 set/change 使用 ngOnInit
生命周期钩子和 window:resize
变量值] 事件。这是一个例子:
html:
<div fxFlex class="app-content">
This is the content
</div>
<button *ngIf="openFlag" type="button" (click)="sidenav.close(); openFlag = false">Close</button>
<button *ngIf="!openFlag" type="button" (click)="sidenav.open(); openFlag = true">Open</button>
<md-sidenav-container (window:resize)="onResize($event)" style="height: 91vh;background: #FFFFFF">
<md-sidenav #sidenav mode="side" [opened]="openFlag" align="end" style="background: orange">
Sidenav!
</md-sidenav>
</md-sidenav-container>
选项 1:(window:resize)
ts:
ngOnInit(){
this.onResize();
}
onResize(event) {
let width;
if(event != undefined){
width = event.target.innerWidth;
console.log(event.target.innerWidth);
}
else{
console.log(document.body.clientWidth);
width = document.body.clientWidth;
}
if (width >= 1280) {
this.openFlag = true;
}
else {
this.openFlag = false;
}
}
选项 2:弹性布局
我看到你有 fxFlex
表示你正在使用 flex-layout。 Flex-layout 附带 ObservableMedia
(doc)。您也可以使用它来设置 openFlag
.
此选项不需要视图中的 (window:resize)
事件。
ts:
import {MediaChange, ObservableMedia} from "@angular/flex-layout";
constructor(media: ObservableMedia) {
media.asObservable()
.subscribe((change: MediaChange) => {
if(change.mqAlias == 'lg' || change.mqAlias == 'xl'){
this.openFlag = true;
}
else{
this.openFlag = false;
}
});
}