[英]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.