Be informed Angular 11 MatDialog Fundamentals


Of all the Angular Material components, the MatDialog just may be the most complex. At the same time, it is probably also the most versatile of the bunch. Part of the reason is that it’s not a component so much as a service that can be utilized to open modal dialogs with Material Design styling and animations. In this tutorial, we’ll replace the standard JavaScript confirm dialog that we implemented in the Preventing Data Loss In Angular Applications using a CanDeactivate Route Guard tutorial with a MatDialog:

JavaScript Confirm Dialog

Angular Confirm Dialog

Adding MatDialog to the Material Module File

Recall that we placed all of our Angular Material imports in the srcappsharedmodulesmaterialmaterial.module.ts file. We will now add MatDialog to the list:

import {MatDialogModule} from '@angular/material/dialog';

const materialModules = [
  //...
  MatToolbarModule,
  MatDialogModule
];

Creating the ConfirmDialog Component

Part of what makes MatDialog so versatile is that its open() method accepts a component to show in the body of the dialog. You might be tempted to create the component as a child to the one that will call it, but it might be wise to think twice before doing so as we may like to reuse the same dialog in other places within out application in the future. For that reason, I would recommend generating it within the app directory:

ng g c confirm-dialog

In the confirm-dialog.component.ts file, we will modify the constructor to accept a reference to the dialog as well as the data that we will pass to it:

import { Component, Inject, ViewEncapsulation } from '@angular/core';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';

@Component({
  selector: 'app-confirm-dialog',
  templateUrl: './confirm-dialog.component.html',
  styleUrls: ['./confirm-dialog.component.css'],
  // this will allow us to override the mat-dialog-container CSS class
  encapsulation: ViewEncapsulation.None
})
export class ConfirmDialogComponent {

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

Next, we’ll add the contents of the dialog to the confirm-dialog.component.html file:

<div class="dialog-header accent-background">
  <span class="dialog-header-title">{{data.dialogTitle}}</span>
</div>
<div class="dialog-content">
  <p>{{data.dialogMessageLine1}}<br/>
  {{data.dialogMessageLine2}}</p>
</div>
<div class="dialog-footer">
  <button class="standard-button dialog-button" mat-raised-button [mat-dialog-close]="false" cdkFocusInitial>{{data.noButtonText}}</button>
    
  <button mat-raised-button color="primary" [mat-dialog-close]="true">{{data.yesButtonText}}</button>
</div>

Invoking the MatDialog Service

Back in the survey.component.ts file, we’re ready to update the canExit() method to present our custom dialog instead of the native JavaScript confirm dialog. There are three things we need to do to make that happen:

  1. Add a constructor that accepts a MatDialog reference.
  2. Add the openUnsavedChangesDialog() method. It’s responsible for showing the dialog.
  3. Invoke the openUnsavedChangesDialog() method from canExit().

Here is the updated source code for the survey.component.ts file that shows the relevant changes:

// imports
import { MatDialog } from "@angular/material/dialog";
import { ConfirmDialogComponent } from "../confirm-dialog/confirm-dialog.component";

// SatisfactionRatings enum

@Component({
  selector: "app-survey",
  templateUrl: "./survey.component.html",
  styleUrls: ["./survey.component.css"]
})
export class SurveyComponent implements IDeactivateComponent {
  // declarations

  constructor(public dialog: MatDialog) { }

  //methods...

  public canExit(): boolean | Observable<boolean> {
    return this.ngFormRef.dirty
      ? this.openUnsavedChangesDialog()
      : true;
  };

  private openUnsavedChangesDialog(): Observable<boolean> {
    const dialogRef = this.dialog.open(ConfirmDialogComponent, {
      width: '26.5rem',
      data: { 
        dialogTitle: 'Unsaved Changes', 
        dialogMessageLine1: 'You have unsaved changes.',
        dialogMessageLine2: 'Are you sure you want to leave the page?',
        yesButtonText: 'Leave this Page',
        noButtonText: 'Stay on this Page'
      }
    });

    return dialogRef.afterClosed();
  }
}

The openUnsavedChangesDialog() Method Explained

There’s a lot going on in this little method, so let’s unpack it.

The dialog reference that we injected via the constructor provides numerous methods, properties, and event hooks for working with it, the most important of which being the open() method. It accepts the component to display as well as a MatDialogConfig object. That’s where we set the dialog’s appearance and pass along the data object that populates the dialog component.

Organizations must go beyond a piecemeal approach to networking and security. A broad, integrated, and automated platform that secures all edges addresses challenges now and in the future.

The afterClosed() event hook receives an observable that is notified when the dialog is finished closing. We can do whatever processing we need to do after the dialog is closed. In our case, we don’t need to do anything but pass along the value returned by the dialog. That gets set by the two buttons in the footer via the bound [mat-dialog-close] attribute:

<div class="dialog-footer">
  <button class="standard-button dialog-button" mat-raised-button [mat-dialog-close]="false" cdkFocusInitial>{{data.noButtonText}}</button>
  &nbsp;&nbsp;
  <button mat-raised-button color="primary" [mat-dialog-close]="true">{{data.yesButtonText}}</button>
</div>

We then need to add the Observable<boolean> return type to canExit() to accommodate the afterClosed() return value.

Here’s the end result of today’s updates to the Preventing Data Loss In Angular Applications using a CanDeactivate Route Guard demo. To test it, navigate to the Survey page, interact with the form so as to update the underlying model, and then click the Home link:

Conclusion

In this tutorial, we learned how to use the MatDialog, the most complex, and yet most versatile Angular Material component. To do that, we replaced the standard JavaScript confirm dialog that we implemented in the Preventing Data Loss In Angular Applications using a CanDeactivate Route Guard demo with a MatDialog.

Leave a Reply

Your email address will not be published. Required fields are marked *