Components: Not able to close modal dialog using dialogRef.close()

Created on 5 Oct 2017  路  23Comments  路  Source: angular/components

I am opening Modal popup in Angular 4 using Material. whereas it is opening properly but I am not able to close it using dialogRef.close(). I am opening AdminComponent as a popup by clicking on button which is present on Home.Component.html.

Admin.Component.ts-
`import {MdDialog} from '@angular/material';
import {MdDialogRef} from '@angular/material';

export class AdminComponent implements OnInit {
constructor( public dialogRef:MdDialogRef <AdminComponent>, private emergencycontacts: EMTServiceService) { }
closeModal() {
console.log('closing');
this.dialogRef.close();
}
}`

Admin.Component.html-
<td md-dialog-actions> <button md-raised-button (click)="closeModal()" class="btncancel" >Cancel</button></td>

Please help

cannot reproduce

Most helpful comment

@krisparis can you try this in ErrorDialogContainerComponent?

constructor(
  private errorEventService: ErrorEventService,
  private errorDialog: MatDialog,
  private ngZone: NgZone) {
}

ngOnInit() {
  this.errorEventService.changeEmitted$.subscribe(errorToken => {
    this.ngZone.run(() => {
      if (errorToken && errorToken.error && (!this.errorPopupOpen)) {
        this.openDialog();            
      }
    });
  });        
}

All 23 comments

This should work out of the box. There must be some configuration problem with your code. You can also use the matDialogClose to set the button to close the dialog (I'm using the currently recommended - in beta.11 - mat instead of md prefix ):

<button mat-raised-button matDialogClose>Cancel</button>

Having the opposite problem here. I can close with dialogRef.close(), but not with the directive md-dialog-close. Pressing "Yes" closes the dialog, but pressing "No" doesnt.

<md-dialog-actions>
  <button 
    (click)="close()"
    md-raised-button md-dialog-close>
    Yes
  </button>
  <button md-raised-button md-dialog-close>
    No
  </button>
</md-dialog-actions>
export class EditCourseComponent implements OnInit {

  constructor(private dialogRef: MdDialogRef<EditCourseComponent>,
              @Inject(MD_DIALOG_DATA) data: any) {
    console.log('Data', data);
   }

  ngOnInit() {
  }

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

}

@Deltids try mdDialogClose or matDialogClose

@julianobrasil tried using matDialogClose, still not working.
I replaced all md prefix with mat.
Following is my Home.Component from where I am opening AdminComponent as a popup.

Home.Component.html-

<a title="Add new contact" onclick="showDiv()" (click)="openDialog()" ><img class="img-responsive" src="assets/Images/addNew.png"></a>

Home.Component.ts -
`export class HomeComponent implements OnInit {
dialogRef: MdDialogRef;
constructor(private emergencycontacts: EMTServiceService, private router: Router, public dialog: MdDialog) { }

openDialog(){
this.dialogRef = this.dialog.open(AdminComponent);
this.dialogRef.afterClosed().subscribe((result) => {
console.log(result);

});

}
}`

@VishalChorghe Did you import MatDialogModule or MdDialogModule in relevant xxx.Module.ts?

@VishalChorghe are you able to provide a reproduction?

Can confirm that we have the same issue
Also tried 'this.dialog.closeAll()' before opening the second dialog but 'this.dialog.openDialogs' confirms that first one is still open

Hello everyone,

I have the same issue.
Could you tell me if I missed something and if any workaround exist?

I inserted below parts of my code to describe my problems.

Thanks,

Configuration is:

"@angular/animations": "^5.0.2",
"@angular/cdk": "^5.0.0-rc0",
"@angular/common": "^5.0.2",
"@angular/compiler": "^5.0.2",
"@angular/core": "^5.0.2",
"@angular/forms": "^5.0.2",
"@angular/http": "^5.0.2",
"@angular/material": "^5.0.0-rc0",
"@angular/platform-browser": "^5.0.2",
"@angular/platform-browser-dynamic": "^5.0.2",
"@angular/router": "^5.0.2",
"core-js": "^2.5.1",
"npm": "^5.5.1",
"rxjs": "^5.5.2",
"zone.js": "^0.8.18"

In my AppModule, I imported MatDialogModule, declared my dialog components
and added my dialog content component to the array of entryComponents.

  declarations: [
        AppComponent,
    ErrorDialogContainerComponent,
    ErrorDialogContentComponent,
  ],
  entryComponents: [ErrorDialogContentComponent],
  imports: [
    BrowserModule,
    BrowserAnimationsModule, // imported to allow use of Angular animations animations for Material components
    MatButtonModule,
    MatDialogModule,
  ],

Calling dialogRef.close() or clicking outside the dialog does not close it.
The only I found to close it was to open the Chrome console and then move the console top edge using my mouse.
However MatDialog.closeAll() does work for me.
But trying to reference the MatDialof

I put below the code of the following classes:
dialog container component
dialog content component

I put my dialog container component template inside my app component lie written below

<app-error-dialog-container></app-error-dialog-container>
<app-header></app-header>
<router-outlet></router-outlet>

Below is the dialog content template. I tried to use

<span>Error</span>
<button (click)="onClose()"> Close </button>

Dialog Container class
`

import {Component, Inject, OnInit, Input} from '@angular/core';
import {MatDialog, MAT_DIALOG_DATA} from '@angular/material';

import {ErrorEventService} from '../../../error-event.service';
import {ErrorDialogContentComponent} from '../content/error-dialog-content.component';


@Component({
  selector: 'app-error-dialog-container',
  templateUrl: './error-dialog-container.component.html',
  styleUrls: ['./error-dialog-container.component.css']
})
export class ErrorDialogContainerComponent implements OnInit {
    private errorPopupOpen = false;
    constructor(private errorEventService: ErrorEventService, private errorDialog: MatDialog) {
    }
    ngOnInit() {
      this.errorEventService.changeEmitted$.subscribe(
      errorToken => {
        if (errorToken && errorToken.error && (!this.errorPopupOpen)) {
            this.openDialog();            
        }
      });        
    }

    openDialog(): void {
        console.log('openDialog');    
        this.errorPopupOpen = true;
        let dialogRef = this.errorDialog.open(ErrorDialogContentComponent, {
            disableClose : false
        });
        dialogRef.beforeClose().subscribe(result => {
        console.log('The dialog beforeClose');
        });

        dialogRef.backdropClick().subscribe(result => {
        console.log('backdropClick');
        console.log(result); // show null.
        });                

        /*
        Have the error
        "Property 'keydownEvents' does not exist on type 'MatDialogRef<ErrorDialogContentComponent>'."
        when below code is commented out

        dialogRef.keydownEvents().subscribe(result => {
        console.log('keydownEvents');
        console.log(result);
        });    
        */

        dialogRef.afterClosed().subscribe(result => {
        console.log('The dialog was closed');
        this.errorPopupOpen = false;
        });

        // this.errorDialog.closeAll(); //works
    }     
}`

Dialog Content class

`
import {Component, Inject, OnInit, Input} from '@angular/core';
import {MatDialog, MatDialogRef, MAT_DIALOG_DATA} from '@angular/material';

@Component({
  selector: 'app-error-dialog-content',
  templateUrl: './error-dialog-content.component.html',
  styleUrls: ['./error-dialog-content.component.css']
})
export class ErrorDialogContentComponent implements OnInit {

  constructor(    public dialogRef: MatDialogRef<ErrorDialogContentComponent>,
    @Inject(MAT_DIALOG_DATA) public data: any) {
  }

  ngOnInit(): void {
  }
   onClose(): void {
    console.log(this.dialogRef.disableClose); // Returns false
    this.dialogRef.close(); // does not close the dialog
  }

}

`

@krisparis can you try this in ErrorDialogContainerComponent?

constructor(
  private errorEventService: ErrorEventService,
  private errorDialog: MatDialog,
  private ngZone: NgZone) {
}

ngOnInit() {
  this.errorEventService.changeEmitted$.subscribe(errorToken => {
    this.ngZone.run(() => {
      if (errorToken && errorToken.error && (!this.errorPopupOpen)) {
        this.openDialog();            
      }
    });
  });        
}

@willshowell
Thanks a lot! It now works well!
The dialog now disappears when I click on my close button or when I click outside the dialog.

So, just to know,
was I doing something wrong ?
Or was it maybe because I was trying to open a dialog from inside a subscribe() method ?

Again, thanks :)

@krisparis It is related to your ErrorEventService. I'm assuming you're implementing ErrorHandler there or elsewhere, and handleError is called by angular outsize the zone. There have been similar issues with dialogs and snackbars. AFAIK you're not doing anything wrong, but you should be aware that any UI effects from handleError need to re-enter the zone.

@VishalChorghe @mackelito could your issues be related to this as well?

@willshowell

Yes, I did almost that.
Actually I have a class AppErrorHandler that extends ErrorHandler.
I inserted the code at the bottom of this post.

And in my AppModule, I added the line below into my providersarray
{provide: ErrorHandler, useClass: AppErrorHandler},

import {ErrorHandler } from '@angular/core';
import {Injectable} from '@angular/core';


import {ErrorEventService} from './error-event.service';

@Injectable()
export class AppErrorHandler extends ErrorHandler {
    constructor(private errorEventService: ErrorEventService){
        super(false);
    }
    public handleError(error: any): void {
        this.errorEventService.emitChange({
              error: error
          });       
    }
}

@willshowell

For the sake of trying, I temporarly _removed my ErrorHandlersubclass from my app and the use of the ngZone instance_ from my dialog container class (so back to my original code).
I now handle the error at its origin like shown at the bottom of this post.

In that case also, the dialog disappears after a click on the close button or outside the dialog.

You said

you should be aware that any UI effects from handleError need to re-enter the zone.

  • So do you think it's better for now to handle my errors locally without a custom ErrorHandler?

    • until it gets fixed in a future release

  • Or is it better to keep using the ErrorHandler and the Ngzone as you shown in the previous post?

    • even if my app might have to use other dialog components for different use cases

  public loadUsers (options: DataRequestOptions) {
    this.userService.getUsers(options).subscribe(dataAndMeta => {
      this.meta = dataAndMeta.meta;
      this.dataAndMetaChange.next(this.convertUsersToRoleMembers(dataAndMeta.data));
    },
      error => {
        // Old code: throw new Error('err');
        this.errorEventService.emitChange({ error: error });
      }
    )  
  }

@krisparis I think everything on Angular and Angular Material's end is working as intended, so I wouldn't await a fix (maybe a docs improvement here at best).

Every use case is different - I think the expected use of the ErrorHandler is to facilitate logging or extra ajax calls or similar, which don't need to operate within the angular zone. You've chosen to bring the error callback into your components (material dialog), so you should do so inside the zone. If you are using errorEventService.changeEmitted$ exclusively for UI updates, I would suggest this:

@Injectable()
export class AppErrorHandler extends ErrorHandler {

  constructor(private errorEventService: ErrorEventService, private ngZone: NgZone){
    super(false);
  }

  handleError(error: any): void {
    // Bring error handling back into the zone so components are aware of error events
    this.ngZone.run(() => {
      this.errorEventService.emitChange({ error });     
    });
  }
}

But also I have only a moderate understanding of how zones work and should be utilized so take it with a grain of salt 馃槃

Closing this since it's not directly related to Angular Material.

Check out this article for some background on understand zones:
https://blog.thoughtram.io/angular/2016/02/01/zones-in-angular-2.html

Hi,

I'm having a similar problem but the NgZone solution doesn't work.

I've a simple dialog that shows a message and a QRCode and has an "OK" button to close it just for user experience.

The problem is that there's no way to close the dialog, nothing works: clicks outside, pressing ESC key or pressing the OK button are useless.

Here's the code:

TokenComponent
where openDialog is fired on a simple FAB click.

openDialog() {
    let dialogRef = this.dialog.open(NewTokenDialogComponent, {
      disableClose: false,
      data: { userID: "a-user-id" }
    });

    dialogRef.beforeClose().subscribe((result: string) => {
      console.log('Right before close', result);
    });
    dialogRef.afterClosed().subscribe(result => {
      console.log('The dialog was closed', result);
    });
}

Then I have this modal:

<h1 mat-dialog-title>Lorem Ipsum</h1>
<div mat-dialog-content>
  <p>
    Lorem ipsum dolor sit amet
  </p>
  <div style="text-align:center;">
    <img [src]="safeUrl" />
  </div>
</div>
<div mat-dialog-actions>
  <button mat-button [mat-dialog-close]>OK</button>
</div>

The modal gets opened but I can't find a way to close it.

I've tried creating a simple StackBlitz and I realised that it actually works: https://stackblitz.com/edit/test-dialog-closing

I'm honestly confused but I think it could be related to this issue since the symptoms are similar.

Note: the close button in the example is using [mat-dialog-close], I've also tried matDialogClose and a custom function that calls this.dialogRef.close() which is the one used in the stackblitz.

A difference between the stackblitz and my local project is that the dialog component and the "container" component are in two separate files but I guess everything is properly included since I can see the dialog properly rendered.

Thank you!

PS: I'm a super newbie with Angular 5 and Material 2, I started my first project two days ago after a few years working with Angular 1 and no background of material design.

PPS: Do not scan the QRCode, I copy-pasted the first result from google search of "qrcode", I do not know that's inside 馃槥

I've found out that this problem was related to an error occurring on another component..

In particular I have a TypeError during the rendering of a MatTable in the same page. This error causes the Dialog not to work properly once opened.

If you want to investigate this weird behaviour of Dialog when an error occurs I can provide further information.

@fredmaggiowski
I may be having a similar problem. My dialog does not close when the closing buttons are clicked either, and I have a MatTable in the parent component, that does not re-render if I try to select/highlight a row programatically - i had to use ChangeDetectorRef.detectChanges() to fire off the re-render - which I think I'm having to do because of some silent error that I can't see in the dev console. I was wondering what kind of a TypeError you found. Was it evident in the console?

Hi @amreshprasad I honestly do not remember neither what the TypeError was about nor whether it was evident in the console.

I guess that yes, the error was visible in the console, but I felt like I could ignore it while it was actually causing problems to the rest of the web app (the whole dialog-not-closing stuff) but I've very bad at remembering so I don't know :(.

@willshowell Thanks man! ngZone works like a charm. You saved me a lot of pain and suffering haha.

@willshowell And once again thank you! Your solution with returning into correct zones works like a charm.
A bit of background info of my issue for next people coming here:

  • I am using an Angular Material Dialog. This dialog is opened from SignalR event.
  • Failed behavior was:
    1 - dialog is immediately opened after SignalR event received. But it was empty (no data rendered). Data was rendered with dealy of 2-6 seconds.
    2 - Pressing close button did not close dialog immediately, a delay of 2-6 seconds was present.

@willshowell @Va-alexander
You saved my life... I've been fighting with this dialog for a good hour and a half... I kinda had a feeling where the problem was but didn't even knew about ngZone... it solved my problem and I'm sure it will be handy for a lot of other stuff..

For reference for other people:

  • MatDialog closing after a couple seconds delay

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

_This action has been performed automatically by a bot._

Was this page helpful?
0 / 5 - 0 ratings

Related issues

vanor89 picture vanor89  路  3Comments

jelbourn picture jelbourn  路  3Comments

crutchcorn picture crutchcorn  路  3Comments

kara picture kara  路  3Comments

michaelb-01 picture michaelb-01  路  3Comments