繁体   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