簡體   English   中英

切換時如何避免ExpressionChangedAfterItHasBeenCheckedError

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

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM