Search code examples
angularangular-materialmaterial-dialog

How to close a mat dialog without a backdrop on clicking outside?


How Can I close the dialog in this stackblitz example (Minimal, Reproducible Example.) by clicking outside ?

This works fine if I remove the property hasBackdrop: false -> Working Stackblitz Example


Solution

  • In a nutshell, you need to do your own click handling - listen to clicks and determine whether or not they are outside the dialog. This allows you to not trap the click event the way that the backdrop does. Here's a StackBlitz example based on yours:

    @Component({
      selector: 'dialog-overview-example',
      templateUrl: 'dialog-overview-example.html',
      styleUrls: ['dialog-overview-example.css'],
    })
    export class DialogOverviewExample {
    
      @HostListener('document:click', ['$event'])
      clickout(event) {
        if (this.clickoutHandler) {
          this.clickoutHandler(event);
        }
      }
    
      animal: string;
      name: string;
    
      clickoutHandler: Function;
    
      dialogRef: MatDialogRef<DialogOverviewExampleDialog>;
    
      constructor(public dialog: MatDialog) {}
    
      openDialog(): void {
        setTimeout(() => {
          this.dialogRef = this.dialog.open(DialogOverviewExampleDialog, {
            width: '250px',
            hasBackdrop: false
          });
    
          this.dialogRef.afterOpened().subscribe(() => {
            this.clickoutHandler = this.closeDialogFromClickout;
          });
    
          this.dialogRef.afterClosed().subscribe(() => {
            this.clickoutHandler = null;
          });
        });
      }
    
      closeDialogFromClickout(event: MouseEvent) {
        const matDialogContainerEl = this.dialogRef.componentInstance.hostElement.nativeElement.parentElement;
        const rect = matDialogContainerEl.getBoundingClientRect()
        if(event.clientX <= rect.left || event.clientX >= rect.right || 
            event.clientY <= rect.top || event.clientY >= rect.bottom) {
          this.dialogRef.close();
        }
      }
    }
    
    @Component({
      selector: 'dialog-overview-example-dialog',
      templateUrl: 'dialog-overview-example-dialog.html',
    })
    export class DialogOverviewExampleDialog {
    
      constructor(
        public hostElement: ElementRef,
        public dialogRef: MatDialogRef<DialogOverviewExampleDialog>,
        @Inject(MAT_DIALOG_DATA) public data: DialogData) {
      }
    
      onNoClick(): void {
        this.dialogRef.close();
      }
    }