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
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
The standard approach for creating an Angular Material Dialog that closes when clicking outside the dialog box (while creating the appearance that there is no backdrop) is to use the built-in library CSS class cdk-overlay-transparent-backdrop
and apply it using the MatDialogConfig
property backdropClass
.
The openDialog
method would be:
openDialog(): void {
const dialogRef = this.dialog.open(DialogOverviewExampleDialog, {
backdropClass: 'cdk-overlay-transparent-backdrop',
hasBackdrop: true,
width: '250px'
});
}
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();
}
}
There are many ways on how to achieve this. One would be listening on window clicks. Stackblitz
export class DialogOverviewExampleDialog {
private inited;
constructor(
public dialogRef: MatDialogRef<DialogOverviewExampleDialog>,
@Inject(MAT_DIALOG_DATA) public data: DialogData) { }
ngOnInit() {
this.dialogRef.afterOpened().subscribe(() => {
this.inited = true;
})
}
@HostListener('window:click')
onNoClick(): void {
if (this.inited) {
this.dialogRef.close();
}
}
}
But I suggest you edit the css for the backdrop, so it remains invisible but the functionality stays.
.cdk-overlay-dark-backdrop {
background: transparent;
}