Create a reusable confirmation dialog in Angular 7, using Angular Material

Posted by

Having a confirmation dialogs is a very common requirement in the applications nowadays. They are used when a specific(in most cases destructive) action is executed, like deleting a specific record.

We don’t want the users of our application to delete something by mistake. That’s why when a delete button is clicked, a dialog box with confirmation message and two buttons appear – one to confirm the action(continue the deletion) and one to stop the deletion.

In this article, you will learn how to implement a reusable confirmation dialog in Angular 7, using Angular Material. We will implement the dialog box as a new shared component, which will be available to be called from the other components(when needed). Extracting it as a separate component will allow us to have the template of our confirmation box and part of the interaction logic in one single place instead of repeating code all over our application.

So, here is my implementation plan:

  1. Create a brand new Angular project (version 7)
  2. Install Angular Material and configure it(import the modules we will need)
  3. Create the reusable confirmation dialog component
  4. Test our solution for both “Yes” and “No” cases

Create a brand new Angular project (version 7)

As you probably already know, creating a project using the @angular/cli is really easy.

 ng new angular-app

In the time of writing this(03/04/2019), I was asked two question by the Cli:

? Would you like to add Angular routing? No

? Which stylesheet format would you like to use? CSS

We will go without routing and stylesheet format – css. Don’t worry if you have chosen a different style, we will be using it only to import our Angular Material theme.

Install Angular Material and configure it(import the modules we will need)

Use the following command to install Angular Material, Angular CDK and Angular Animation(the last two are required by the angular material package in order to work as expected)

npm install --save @angular/material @angular/cdk @angular/animations

When the packages are installed, we can import the dependencies we will be using – BrowserAnimationsModule, MatDialogModule and MatButtonModule

import {MatDialogModule} from '@angular/material/dialog';
import {MatButtonModule} from '@angular/material/button';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';

And include it in the imports array(also in app.module.ts):

 imports: [
    BrowserModule,
    BrowserAnimationsModule,
    MatDialogModule,
    MatButtonModule
  ]

A little clarification – the BrowserAnimations is required by Angular Material, MatButton will be used just for styling purposes in both our dialog and app module and the most important one – MatDialog, will help us to handle the dialog itself.

And the last mandatory step is to include our theme.

I have decided to use the deeppurple-amber by importing it in styles.css (the global styles file)

@import ‘~@angular/material/prebuilt-themes/deeppurple-amber.css’;

Note: Importing the styles of specific theme is a must. Don’t skip this, otherwise some of the material styles will be missing.

Create the reusable confirmation dialog component

Create a new component with name confirmation-dialog using the following command:

ng g c components/shared/confirmation-dialog

This will create the dialog component in a folder ‘shared’ and include it in the app.module.ts declarations array.

An important thing to consider here is that the MatDialog module instantiates components at run-time. Because of that, Angular will need some extra information from us. For any component loaded into a dialog, the component class(in our case ConfirmationDialogComponent) have to be included into the list of entry component in our NgModule definition.(app.module.ts)

The final version of the app.module.ts should be:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { MatDialogModule } from '@angular/material/dialog';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { MatButtonModule } from '@angular/material/button';

import { AppComponent } from './app.component';
import { ConfirmationDialogComponent } from './components/shared/confirmation-dialog/confirmation-dialog.component';

@NgModule({
  declarations: [
    AppComponent,
    ConfirmationDialogComponent
  ],
  imports: [
    BrowserModule,
    BrowserAnimationsModule,
    MatDialogModule,
    MatButtonModule
  ],
  entryComponents: [
    ConfirmationDialogComponent
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

After these configurations, it’s time to fill the component itself with some code.

Include the following code in confirmation-dialog.component.html

<div mat-dialog-content>
 {{message}}
</div>
<div mat-dialog-actions>
  <button mat-button (click)="onNoClick()">No</button>
  <button mat-button [mat-dialog-close]="true" cdkFocusInitial>Yes</button>
</div>

This will be our dialog template. Nothing fancy as this is not the purpose of this tutorial.

Basically the dialog content is divided on two parts:

The first one is the confirmation message(which we will receives as a parameter from the component opening the dialog) and the next one is the actions bar. The actions are “Yes” and “No”. When the “No” button is clicked, it will simply close the dialog.

In case of “Yes” clicked, a parameter true will be emitted to all who has subscribed to afterClosed() method of the dialogRef. The “true” value passing is done by  [mat-dialog-close]=”true”..

We subscribe to this method in the component who is opening the dialog which we will cover in the next step.

In order to finish with the component configuration, we have to include the following code in confirmation-dialog.component.ts

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

@Component({
  selector: 'app-confirmation-dialog',
  templateUrl: './confirmation-dialog.component.html',
  styleUrls: ['./confirmation-dialog.component.css']
})
export class ConfirmationDialogComponent {
  constructor(
    public dialogRef: MatDialogRef<ConfirmationDialogComponent>,
    @Inject(MAT_DIALOG_DATA) public message: string) { }

  onNoClick(): void {
    this.dialogRef.close();
  }
}

The constructor method is doing two things, receive the reference to the dialog we are currently opening and injecting the message that has to be displayed on this dialog. Both of them are passed by the component, who is opening the dialog.

In addition to the constructor, we are also implementing a simple onNoClick method who is handling the “No” button click. He is doing only one thing – closing the dialog by calling the method close(), provided by Angular Material.

Phew 🙂 That’s it, let’s continue with details how to use this component from other components in our application.

Test our solution for both “Yes” and “No” cases

Using the component we have created a few seconds ago is not a rocket science, but has some details that we need to know.

Let’s change the app.component.html to the following:

<button mat-button (click)="openDialog()">Confirm box</button>

We will use this button to trigger openDialog method, who will open the confirmation dialog using our previously created component.

Here is the code we need in app.component.ts

import { Component } from '@angular/core';
import { MatDialog } from '@angular/material';

import { ConfirmationDialogComponent } from './components/shared/confirmation-dialog/confirmation-dialog.component';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'angular-confirmation-dialog';

  constructor(public dialog: MatDialog) {}

  openDialog(): void {
    const dialogRef = this.dialog.open(ConfirmationDialogComponent, {
      width: '350px',
      data: "Do you confirm the deletion of this data?"
    });

    dialogRef.afterClosed().subscribe(result => {
      if(result) {
        console.log('Yes clicked');
        // DO SOMETHING
      }
    });
  }
}

By importing the MatDialog in our component, we can open dialog(or more than one) by simply using the .open method delivered to us by Angular Material. This method has one mandatory parameter – the component to be loaded in the dialog box. In our case we are passing the ConfirmationDialogComponent created in the previous chapter. The second parameter is optional and represent the config object. In the example above we are using it to pass the width of the dialog and data, which represents the confirmation message. Instead of string, a common practice is to pass an object with different data there(you can pass title and message or whatever you need in your component to be displayed).

The opening method itself returns an instance of MatDialogRef. The MatDialogRef provides a handle on the opened dialog. This handler can be used to close the dialog programmatically or to subscribe and receive a notification when the dialog is closed.

In our openDialog method, we are using the last one – subscribing and waiting for our dialog to be closed. As per our configuration(check part 3), when the “Yes” button is clicked, a true value will be passed to this handler. In case of “No”, there will be no value, i.e. undefined.

In both cases(yes or no clicked) the afterClosed handler will be executed, that’s why we are using an if statement to check if the result is truthy. If it is, we can continue with the action – to delete something or whatever we need to do.

And actually, we are done.

To check if everything works as expected, start the project by:

ng serve

You should be able to see a Confirm Box button. When you click it, the dialog should appear:

You will be able to close it by clicking the No, Yes buttons or outside the dialog.

I hope you enjoyed this tutorial.

You can see the full code here: https://github.com/vikobg/first-class-js/tree/master/angular-confirmation-dialog

And a working example here – https://firstclassjs.com/tutorials/angular-confirmation-dialog/

Good luck!