I have a general Alert Dialog component that I use for various purposes throughout an Angular application (simplified)...
@Component({
selector: 'app-alert-dialog',
template: `<mat-dialog-content>{{message}}</mat-dialog-content>
<mat-dialog-actions align="end">
<button mat-raised-button mat-dialog-close>{{buttonText}}</button>
</mat-dialog-actions>`
})
export class AlertDialog {
message: string = 'An unspecified error has occurred';
buttonText = 'Cancel';
constructor(
@Inject(MAT_DIALOG_DATA)
private data: {
message: string;
buttonText: string;
},
private dialogRef: MatDialogRef<AlertDialog>
) {
if (data?.message) this.message = data.message;
if (data?.buttonText) this.buttonText = data.buttonText;
}
}
The dialog windows specify default options in the app.module providers:
@NgModule({
...
providers: [
{ provide: ErrorHandler, useClass: ErrorHandlerService },
// default options for dialogs
{
provide: MAT_DIALOG_DEFAULT_OPTIONS,
useValue: {
disableClose: true,
hasBackdrop: true
}
}
]
})
I also implement a custom ErrorHandler provider that displays relevant errors through the Alert Dialog.
@Injectable({
providedIn: 'root'
})
export class ErrorHandlerService extends ErrorHandler {
constructor(private dialog: MatDialog) {
super();
}
handleError(err: any): void {
console.error(err);
this.dialog.open(AlertDialog, {
data: { message: err.message }
});
}
}
The errors displayed are frequently ones returned by the back-end server asynchronously.
In the case of an error being thrown asynchronously, the dialog does not close in response to the button (even with a (click)="closeDialog()"
handler) unless you click the button and then also click elsewhere off the button.
I have a StackBlitz project that demonstrates the issue here: https://stackblitz.com/edit/angular-ivy-b3fqjj
Is there a way to close the dialog opened asynchronously with a single button click?
Use ngZone. Improved code:
constructor(private dialog: MatDialog, private ngZone: NgZone) {
super();
}
handleError(err: any): void {
console.error(err);
this.ngZone.run(() => {
this.dialog.open(AlertDialog, {
data: { icon: 'Error', message: err.message, buttonText: 'Uh oh!' }
});
});
}
For more information see answer.