[英]How to avoid ExpressionChangedAfterItHasBeenCheckedError when using [(ngModel)] binding on textarea
[英]How to avoid ExpressionChangedAfterItHasBeenCheckedError when toggle
在我的Angular 4项目中,我想基于切换按钮的值显示2个表中的一个,如果为false,则显示第一个表,如果为true,则显示第二个表。
我正在像这样的div中使用primeng datatable:
<div *ngIf="checked">
<p-dataTable [value]="models" [rows]="10"[paginator]="true"....
</div>
切换是
<mat-slide-toggle labelPosition="before" [(ngModel)]="checked">
{{first table }}</mat-slide-toggle>
但是,当我单击切换按钮时,我有:
错误错误:ExpressionChangedAfterItHasBeenCheckedError:检查表达式后,表达式已更改。 先前的值:“ false”。 当前值:“ true”。
那么如何避免这个错误呢?
这是整个组件:
<div class="main-content">
<div class="container-fluid">
<div class="row">
<div class="col-md-12">
<div class="card">
<div class="card-header card-header-icon"
data-background-color="main-theme-color">
<i class="material-icons">euro_symbol</i>
</div>
<div class="card-content">
<h4 class="card-title">{{'movement.table.titles.header' |
translate }}</h4>
<div class="row">
<div class="col-md-2 col-md-offset-10">
<!-- matTooltip="Like" [matTooltipPosition]="'left'"
title="{{'movement.table.tooltips.add' | translate }}"-->
<button type="button" class="btn btn-info btn-round pull-right"
(click)="routeToView(['/movements/new'])"
matTooltip="{{'movement.table.tooltips.add' | translate }}"
[matTooltipPosition]="'above'"
[matTooltipShowDelay]="tooltipShowDelay"
[matTooltipHideDelay]="tooltipHideDelay">
<span class="btn-label"> <i class="material-icons">add</i>
</span>
</button>
</div>
</div>
<div class="row">
<div class="col-md-2">
<mat-slide-toggle labelPosition="before" [(ngModel)]="checked">{{'movement.table.toggle.competenceview'
| translate }}</mat-slide-toggle>
</div>
<div class="col-md-2">
<label class="pull-right">{{'movement.table.toggle.financialview'
| translate }}</label>
</div>
</div>
<div class="col-md-12" *ngIf="checked">
<div class="content table-responsive">
<p-dataTable #dt [value]="models" [rows]="defaultPageSize"
[paginator]="true" [rowsPerPageOptions]="pageSizeOptions"
[responsive]="true" resizableColumns="true" [lazy]="true"
[totalRecords]="totalElements" sortField="createdDate"
[sortOrder]="-1" (onLazyLoad)="loadDataIntoTable($event)"
[loading]="loader" reorderableColumns="true"> <p-column
field="createdDate" [sortable]="true"
header="{{'movement.table.headers.date' | translate }}">
<ng-template let-col let-date="rowData" pTemplate="body">
<span> {{date[col.field] | formatdate | date
:('pattern.datehourmin' | translate)}} </span> </ng-template></p-column> <p-column
field="currencyDate" [sortable]="true"
header="{{'movement.table.headers.currencydate' | translate }}">
<ng-template let-col let-date="rowData" pTemplate="body">
<span> {{date[col.field] | formatdate | date
:('pattern.date' | translate)}} </span> </ng-template></p-column> <p-column field="description"
header="{{'movement.table.headers.description' |
translate }}"
[sortable]="true"> <ng-template
let-movement="rowData" pTemplate="body"> <span
*ngIf="movement.refundId || movement.ticketBundleId"
class="crosslink" (click)="selectDescription(movement)">{{movement.description}}</span>
<span
*ngIf="movement.refundId === undefined && movement.ticketBundleId === undefined">{{movement.description}}</span>
</ng-template> </p-column> <p-column field="paymentTypeName"
header="{{'movement.table.headers.paymenttypename' |
translate }}"
[sortable]="true"></p-column> <p-column field="amount"
header="{{'movement.table.headers.amount' | translate }}"
[sortable]="true"> <ng-template let-col
let-amount="rowData" pTemplate="body"> <span
[style.color]="amount[col.field] < 0 ? 'red' : 'green'">
{{amount[col.field] | currency:'EUR':true}} </span> </ng-template></p-column> <p-column
styleClass="col-button"> <ng-template
let-model="rowData" pTemplate="body">
<div class="text-center">
<span><button
class="btn btn-simple btn-success btn-icon edit"
(click)="selectModel(model)"
matTooltip="{{'movement.table.tooltips.view' | translate }}"
[matTooltipPosition]="'left'"
[matTooltipShowDelay]="tooltipShowDelay"
[matTooltipHideDelay]="tooltipHideDelay">
<i class="material-icons">dvr</i>
</button> </span>
</div>
</ng-template> </p-column> </p-dataTable>
</div>
</div>
<div class="col-md-12" *ngIf="!checked">
<div class="content table-responsive">
<p-dataTable #dt [value]="models" [rows]="defaultPageSize"
[paginator]="true" [rowsPerPageOptions]="pageSizeOptions"
[responsive]="true" resizableColumns="true" [lazy]="true"
[totalRecords]="totalElements" sortField="createdDate"
[sortOrder]="-1" (onLazyLoad)="loadDataIntoTable($event)"
[loading]="loader" reorderableColumns="true"> <p-column
field="createdDate" [sortable]="true"
header="{{'movement.table.headers.date' | translate }}">
<ng-template let-col let-date="rowData" pTemplate="body">
<span> {{date[col.field] | formatdate | date
:('pattern.datehourmin' | translate)}} </span> </ng-template></p-column> <p-column
field="currencyDate" [sortable]="true"
header="{{'movement.table.headers.currencydate' | translate }}">
<ng-template let-col let-date="rowData" pTemplate="body">
<span> {{date[col.field] | formatdate | date
:('pattern.date' | translate)}} </span> </ng-template></p-column> <p-column field="description"
header="{{'movement.table.headers.description' |
translate }}"
[sortable]="true"> <ng-template
let-movement="rowData" pTemplate="body"> <span
*ngIf="movement.refundId || movement.ticketBundleId"
class="crosslink" (click)="selectDescription(movement)">{{movement.description}}</span>
<span
*ngIf="movement.refundId === undefined && movement.ticketBundleId === undefined">{{movement.description}}</span>
</ng-template> </p-column> <p-column field="paymentTypeName"
header="{{'movement.table.headers.paymenttypename' |
translate }}"
[sortable]="true"></p-column> <p-column field="amount"
header="{{'movement.table.headers.amount' | translate }}"
[sortable]="true"> <ng-template let-col
let-amount="rowData" pTemplate="body"> <span
[style.color]="amount[col.field] < 0 ? 'red' : 'green'">
{{amount[col.field] | currency:'EUR':true}} </span> </ng-template></p-column> <p-column
styleClass="col-button"> <ng-template
let-model="rowData" pTemplate="body">
<div class="text-center">
<span><button
class="btn btn-simple btn-success btn-icon edit"
(click)="selectModel(model)"
matTooltip="{{'movement.table.tooltips.view' | translate }}"
[matTooltipPosition]="'left'"
[matTooltipShowDelay]="tooltipShowDelay"
[matTooltipHideDelay]="tooltipHideDelay">
<i class="material-icons">dvr</i>
</button> </span>
</div>
</ng-template> </p-column> </p-dataTable>
</div>
</div>
</div>
</div>
<!-- end card -->
</div>
<!-- end col-md-12 -->
<!-- end row -->
</div>
</div>
</div>
打开PrimeNG对话框时,特别是当下拉列表或单选按钮是第一个吸引焦点的组件时,出现了ExpressionChangedAfterItHasBeenCheckedError
。 从这里的线程:
https://github.com/primefaces/primeng/issues/4139
...看起来像是PrimeNG错误,不只是人们使用PrimeNG做错了什么。
我找到了一种我不为之疯狂的解决方法,但现在看来似乎已经为我完成了工作:
// Patches for PrimeNG focus bugs.
import { Dropdown, RadioButton } from 'primeng/primeng';
const originalDropdownOnInputFocus = Dropdown.prototype.onInputFocus;
Dropdown.prototype.onInputFocus = function(event: any): void {
setTimeout(() => {
originalDropdownOnInputFocus.call(this, event);
});
};
const originalRadioButtonOnFocus = RadioButton.prototype.onFocus;
RadioButton.prototype.onFocus = function(event: any): void {
setTimeout(() => {
originalRadioButtonOnFocus.call(this, event);
});
};
这并不意味着要进行详尽的修复,而只是解决我在自己的应用程序中遇到的特定问题,重点是p-dropdown和p-radioButton。 希望可以遵循此模式来修复其他错误。
当然,我会急切地等待PrimeNG本身的真正修复,因此我可以删除此解决方法。
我使用以下解决方法来避免出现类似问题。 我增加了一个参考ChangeDetectorRef
在构造服务并调用它的detectChanges()
方法在组件与延迟构造函数的最后一件事:
import { ChangeDetectorRef } from '@angular/core';
....
constructor(....,
private cdr: ChangeDetectorRef) {
....
setInterval(() => {
this.cdr.detectChanges();
}, 1000);
}
这已经工作了好几次了。 如果错误没有消失,则可能必须调试代码并找到发生错误的位置,然后再调用detect changes方法。 例如,如果您知道错误发生在yourMethod()
的特定位置,那么您可能必须像下面这样修改方法:
yourMethod(param):returnType {
....
//spot at which the error occurs
setInterval(() => {
this.cdr.detectChanges();
}, 10);
....
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.