whwanthony
whwanthony

Reputation: 41

ExpressionChangedAfterItHasBeenCheckedError in mat-table when there is *ngIf in column

I am getting ExpressionChangedAfterItHasBeenCheckedError when using mat-table filter and one of my column using

<mat-icon *ngIf="parseString(element.blacklisted)" matTooltip="{{'black_listed'|translate}}" class="warning">thumb_down</mat-icon>

I am using Angular 7 and custom responsive style. I found if I remove this *ngIf code, the responsive style still give me same error with this line of code

<span class="mobile-label">{{'name_label'|translate}}:</span>

the error message is like this:

ERROR Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'ngIf: undefined'. Current value: 'ngIf: false'. It seems like the view has been created after its parent and its children have been dirty checked. Has it been created in a change detection hook ?
    at viewDebugError (core.js:16657)
    at expressionChangedAfterItHasBeenCheckedError (core.js:16645)
    at checkBindingNoChanges (core.js:16747)
    at checkNoChangesNodeInline (core.js:19618)
    at checkNoChangesNode (core.js:19607)
    at debugCheckNoChangesNode (core.js:20211)
    at debugCheckDirectivesFn (core.js:20139)
    at Object.eval [as updateDirectives] (LoanReportComponent.html:37)
    at Object.debugUpdateDirectives [as updateDirectives] (core.js:20128)
    at checkNoChangesView (core.js:19506)

here is my html code

<div>
      <app-alert></app-alert>
      <br />
      <app-loader></app-loader>

      <mat-form-field class="prefix-indent">
        <mat-icon matPrefix>search</mat-icon>
        <input matInput class="form-control search-box" (keyup)="updateFilter($event.target.value)" placeholder="{{'filter_label'|translate}}">

      </mat-form-field>
      <!-- Report list -->
      <div *ngIf="transaction_list.length>0">
        <mat-table mat-table #transaction [dataSource]="ds_transaction" matSort>
          <ng-container matColumnDef="name">
            <mat-header-cell *matHeaderCellDef mat-sort-header> {{'name_label'|translate}} </mat-header-cell>
            <mat-cell *matCellDef="let element">
              <span class="mobile-label">{{'name_label'|translate}}:</span>
              {{element.customer_full_name}}<mat-icon *ngIf="parseString(element.blacklisted)" matTooltip="{{'black_listed'|translate}}" class="warning">thumb_down</mat-icon>
            </mat-cell>
          </ng-container>

          <ng-container matColumnDef="transaction_dt">
            <mat-header-cell *matHeaderCellDef> {{'transaction_date'|translate}} </mat-header-cell>
            <mat-cell *matCellDef="let element">
              <span class="mobile-label">{{'transaction_date'|translate}}:</span>
              {{element.transaction_dt}}
            </mat-cell>
          </ng-container>
          <ng-container matColumnDef="application_fee">
            <mat-header-cell *matHeaderCellDef> {{'application_fee'|translate}} </mat-header-cell>
            <mat-cell *matCellDef="let element">
              <span class="mobile-label">{{'application_fee'|translate}}:</span>
              {{element.application_fee}}
            </mat-cell>
          </ng-container>
          <ng-container matColumnDef="principal">
            <mat-header-cell *matHeaderCellDef> {{'principal_label'|translate}} </mat-header-cell>
            <mat-cell *matCellDef="let element">
              <span class="mobile-label">{{'principal_label'|translate}}:</span>
              {{element.principal}}
            </mat-cell>
          </ng-container>

          <ng-container matColumnDef="currency_code">
            <mat-header-cell *matHeaderCellDef> {{'currency_code'|translate}} </mat-header-cell>
            <mat-cell *matCellDef="let element">
              <span class="mobile-label">{{'currency_code'|translate}}:</span>
              {{element.currency_code}}
            </mat-cell>
          </ng-container>

          <ng-container matColumnDef="total_interest_paid">
            <mat-header-cell *matHeaderCellDef> {{'total_interest_paid'|translate}} </mat-header-cell>
            <mat-cell *matCellDef="let element">
              <span class="mobile-label">{{'total_interest_paid'|translate}}:</span>
              {{element.total_interest_paid}}
            </mat-cell>
          </ng-container>

          <ng-container matColumnDef="total_late_fee_paid">
            <mat-header-cell *matHeaderCellDef> {{'total_late_fee_paid'|translate}} </mat-header-cell>
            <mat-cell *matCellDef="let element">
              <span class="mobile-label">{{'total_late_fee_paid'|translate}}:</span>
              {{element.total_late_fee_paid}}
            </mat-cell>
          </ng-container>

          <ng-container matColumnDef="principal_paid">
            <mat-header-cell *matHeaderCellDef> {{'principal_paid'|translate}} </mat-header-cell>
            <mat-cell *matCellDef="let element">
              <span class="mobile-label">{{'principal_paid'|translate}}:</span>
              {{element.principal_paid}}
            </mat-cell>
          </ng-container>

          <ng-container matColumnDef="total_balance_paid">
            <mat-header-cell *matHeaderCellDef> {{'total_balance_paid'|translate}} </mat-header-cell>
            <mat-cell *matCellDef="let element">
              <span class="mobile-label">{{'total_balance_paid'|translate}}:</span>
              {{element.total_balance_paid}}
            </mat-cell>
          </ng-container>

          <ng-container matColumnDef="interest_rate">
            <mat-header-cell *matHeaderCellDef> {{'interest_rate'|translate}} </mat-header-cell>
            <mat-cell *matCellDef="let element">
              <span class="mobile-label">{{'interest_rate'|translate}}:</span>
              {{element.interest_rate}}
            </mat-cell>
          </ng-container>

          <ng-container matColumnDef="cashed_out">
            <mat-header-cell *matHeaderCellDef> {{'paid_off'|translate}} </mat-header-cell>
            <mat-cell *matCellDef="let element">
              <span class="mobile-label">{{'paid_off'|translate}}:</span>
              {{element.cashed_out}}
            </mat-cell>
          </ng-container>

          <ng-container matColumnDef="status">
            <mat-header-cell *matHeaderCellDef> {{'status_label'|translate}} </mat-header-cell>
            <mat-cell *matCellDef="let element">
              <span class="mobile-label">{{'status_label'|translate}}:</span>
              {{getStatus(element.approval_status)}}
            </mat-cell>
          </ng-container>

          <ng-container matColumnDef="action">
            <mat-header-cell *matHeaderCellDef> </mat-header-cell>
            <mat-cell *matCellDef="let element">
              <button mat-raised-button (click)="lookDetail(element)" matTooltip="{{'view_detail'|translate}}" *ngIf="isAdmin">
                <mat-icon>
                  more_horiz
                </mat-icon>
              </button>&nbsp;
              <button mat-raised-button (click)="editLoan(element)" matTooltip="{{'edit_label'|translate}}" *ngIf="isAdmin">
                <mat-icon>
                  edit
                </mat-icon>
              </button>&nbsp;
            </mat-cell>
          </ng-container>

          <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
          <mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>


        </mat-table>
        <mat-paginator #paginator [length]="ds_transaction.length"
                       [pageSize]="10"
                       [pageSizeOptions]="[ 10, 20, 50, 100]"
                       [showFirstLastButtons]="true">
        </mat-paginator>
      </div>

and here are some of my ts code

@ViewChild(MatSort) set matSort(ms: MatSort) {
  this.sort = ms;
  this.setDataSourceAttributes();
}

@ViewChild(MatPaginator) set matPaginator(mp: MatPaginator) {
  this.paginator = mp;
  this.setDataSourceAttributes();
}

setDataSourceAttributes() {
  this.ds_transaction.paginator = this.paginator;
  this.ds_transaction.sort = this.sort;

  if (this.paginator && this.sort) {
    this.updateFilter('');
  }
}

ngOnInit() {
    this._userService.currentUser.takeUntil(this.ngUnsubscribe).subscribe(user => {
      if (!user) {
        this.router.navigate(['/logout']);
      } else {
        this.isAdmin = user.isAdmin;
        this.isEmployee = user.isEmployee;
        if (this.type == 'daily') {
          this.startDate = new Date();
          this.getReport();
        }
        this.translate.get('pending_label').takeUntil(this.ngUnsubscribe).subscribe(value => {

          this.pending_label = value;
          this.approved_label = this.translate.instant('approved_label');
          this.denied_label = this.translate.instant('denied_label');
        });
      }
    });
}

updateFilter(filterValue: string) {

    this.ds_transaction.filter = filterValue.trim().toLowerCase();



  if (this.ds_transaction.paginator) {
    this.ds_transaction.paginator.firstPage();
  }
}

getReport(): void {
  let sDate: string = '';
  let eDate: string = '';
  let reportName: string = '';
  if (this.type == 'daily') {
    sDate = this.datepipe.transform(this.startDate, 'yyyy-MM-dd');
    eDate = this.datepipe.transform(this.startDate, 'yyyy-MM-dd');
    reportName = 'REPORT_DAILY_ACTIVE_LOAN_TRANSACTIONS';
  } else {
    sDate = this.datepipe.transform(this.startDate, 'yyyy-MM-dd');
    eDate = this.datepipe.transform(this.endDate, 'yyyy-MM-dd');
    reportName = 'REPORT_DATE_RANGE_ACTIVE_LOAN_TRANSACTIONS';
  }
  this._backendService.getLoanReport(this._userService.getToken(), sDate, eDate, reportName)
    .takeUntil(this.ngUnsubscribe)
    .subscribe(response => {
      this.transaction_list = response.loan_transactions;
      console.log(this.transaction_list);
      if (this.transaction_list && this.transaction_list.length > 0 && this.transaction_list[0].transaction_id > 0) {
        this.ds_transaction = new MatTableDataSource<any>(this.transaction_list);
      } else {
        this.ds_transaction = new MatTableDataSource<any>();

      }
    }, (error: any) => {
      let msg = error.message ? error.message : error;
      this.alertService.error(msg);
      this._errService.handleError(error);
      this._loader.display(false);
    }, () => {
      this._loader.display(false);
    });
}

thank you very much for your help.

Upvotes: 2

Views: 1741

Answers (1)

Tushar
Tushar

Reputation: 2078

Add following line in your @Component object : changeDetection: ChangeDetectionStrategy.OnPush

like this :

@Component({
  changeDetection: ChangeDetectionStrategy.OnPush,
  selector: 'app-selector',
  templateUrl: './selector.component.html',
  styleUrls: ['./selector.component.scss']
})

And import ChangeDetectionStrategy from '@angular/core'

Upvotes: 5

Related Questions