11

I have read several answers, and I have tried many but I can't seem to get this to work. In my angular 6 app, I try to open a MatDialog but I receive this error:

ERROR Error:
ExpressionChangedAfterItHasBeenCheckedError:
Expression has changed after it was checked. Previous value: '@slideDialog: enter'. Current value: '@slideDialog: exit'.

When I debug the app and click the checkout button, the MatDialog opens and then after stepping through a few more lines it closes. When running the app without breakpoints, you never see the dialog open at all.

Here is the template file:

<div>
  <button id="cancelButton" mat-raised-button (click)="clearCart()">Cancel</button>
  <button id="checkoutButton" mat-raised-button color="primary" (click)="openCheckoutDialog(dataSource)" [disabled]="isTableEmpty()">Checkout</button>
</div>

When I click the button with the id "checkoutButton" it calls openCheckoutDialog()

Here is my class where openCheckoutDialog is called:

import { Component, OnInit, ChangeDetectorRef  } from '@angular/core';

@Component({
  selector: 'app-shopping-cart',
  templateUrl: './shopping-cart.component.html',
  styleUrls: ['./shopping-cart.component.css']
})
export class ShoppingCartComponent implements OnInit {

  dataSource: MatTableDataSource<Item>;
  itemList: Item[] = [];

  constructor(public dialog: MatDialog, private cdr: ChangeDetectorRef) { }

  openCheckoutDialog(): void {
    const dialogRef = this.dialog.open(ReviewItemListComponent, {
      width: '250px',
      data: this.itemList
    });
    // this.cdr.detectChanges();

    dialogRef.afterClosed().subscribe(result => {
      console.log(`Dialog result: ${result}`);
    });
    // this.cdr.detectChanges();
  }
}

I have tried the this.cdr.detectChanges() in those 2 places above, but I would still receive the error.

Here is my ReviewItemListComponent template (dialog when the checkout button is clicked):

<div>
  <h1 mat-dialog-title>
    Are you sure?
  </h1>

  <mat-dialog-actions>
    <button tabindex="-1" mat-raised-button [mat-dialog-close]="true">Cancel</button>
    <button tabindex="-1" mat-raised-button color="primary" (click)="confirm()">Confirm</button>
  </mat-dialog-actions>
</div>

And here is the ReviewItemListComponent class:

import { Component, OnInit, Inject } from '@angular/core';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
import { Item } from '../item';

@Component({
  selector: 'app-review-item-list',
  templateUrl: './review-item-list.component.html',
  styleUrls: ['./review-item-list.component.css']
})
export class ReviewItemListComponent implements OnInit {

  constructor(public dialogRef: MatDialogRef<ReviewItemListComponent>,
    @Inject(MAT_DIALOG_DATA) public data: Item[]) { }

  ngOnInit() {
    this.dialogRef.close();
  }

  confirm(): void {
    this.dialogRef.close();
  }

}

I'm not making any changes to data, which is what most of the questions & answers involve, so how do I resolve this problem regarding opening a MatDialog?

Edit:

Turns out I had pasted this.dialogRef.close() into the wrong method. In this case I put it inside of ngOnInit() when I was creating my review-item-list-component.ts file. So once I open it I close it. This still doesn't explain the error. What is so wrong about closing the recently opened dialog inside of ngOnInit()?

Michael
  • 3,093
  • 7
  • 39
  • 83
  • Odd - those are animation props. Check that the library is compatible with NG6. – bc1105 Jul 11 '18 at 17:40
  • There was a fairly [recent issue filed](https://github.com/angular/material2/issues/10705) for something very similar to this. Which I believe is actually related to this [issue](https://github.com/angular/angular/issues/15634). The work-around seems to be to wrap your dialog creation in a `setTimeout` – Michael Doye Jul 11 '18 at 17:44
  • @bc1105 Check the edit section of my question – Michael Jul 11 '18 at 18:48
  • @Und3rTow I've tried timeouts, check out my edited question – Michael Jul 11 '18 at 18:48
  • There is nothing inherently wrong with closing the dialog in `ngOnInit`. The problem is that the view (dialog) is being modified during the change detection cycle.(which runs twice in dev mode - in prod you would not have this error) If you move `dialog.close()` into `ngAfterViewInit` I believe it should stop that error from being thrown. – Michael Doye Jul 11 '18 at 19:03
  • 99% of `ExpressionChangedAfterItHasBeenCheckedError` can be worked-around adding `changeDetectionRef.detectChanges()` on the parent. – Stavm Sep 21 '18 at 06:36

3 Answers3

7

Use dialog close inside settimeout.

setTimeout(() => {    
    this.dialogRef.close();
}, 0);
Michael
  • 3,093
  • 7
  • 39
  • 83
Manoj Sanjeewa
  • 1,069
  • 1
  • 11
  • 34
2

I know, that your question can already be not actual, but anyway I will answer. The problem is that you call close method in ngOnInit function.

Component doesn't keep up to end itself initialization, when you already call close method. Of course in this case, such error is called.

Please remove this calling in ngOninit, and write correct logic, I mean, write calling close method in separated method, which you'll call there, where it would be needed.

Thank you.

dmitryprogrammer
  • 366
  • 1
  • 11
2

Change [mat-dialog-close] or [matDialogClose] to (click) event. That's works for me.

Update: I guess [matDialogClose] is now working as we expected.