Angular Alert Modal Service Using Material


Description

This is a simple alert modal service that can be used to show alert modals in angular using material. This can be used to confirm user actions like delete, update, etc. fast and easy.

// alert-modal.service.ts
import { CommonModule } from '@angular/common';
import { Component, Inject, Injectable, OnInit } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import {
  MAT_DIALOG_DATA,
  MatDialog,
  MatDialogModule,
} from '@angular/material/dialog';
import { marked } from 'marked';
import { firstValueFrom } from 'rxjs';

interface AlertDataI {
  heading: string;
  body?: string;
  md?: string;
  btn1Name?: string;
  btn2Name?: string;
}

@Injectable({ providedIn: 'root' })
export class AlertModalService {
  constructor(private readonly dialog: MatDialog) {}

  public async open(data: AlertDataI, options = {}) {
    const dialogRef = this.dialog.open(AlertModalComponent, {
      width: '400px',
      data: { data },
      ...options,
    });
    return firstValueFrom(dialogRef.afterClosed());
  }
}

@Component({
  standalone: true,
  imports: [CommonModule, MatDialogModule, MatButtonModule],
  providers: [AlertModalService],
  template: `<div mat-dialog-title style="font-size: 1.2rem">
      {{ alertData.heading }}
    </div>
    <mat-dialog-content class="mat-typography">
      <div *ngIf="alertData.body">{{ alertData.body }}</div>
      <div
        *ngIf="!alertData.body && alertData.md"
        [innerHtml]="alertData.md"
      ></div>
    </mat-dialog-content>
    <mat-dialog-actions align="end">
      <button mat-button [mat-dialog-close]="false" color="warn">
        {{ btn1Name }}
      </button>
      <button
        mat-button
        color="accent"
        [mat-dialog-close]="true"
        cdkFocusInitial
      >
        {{ btn2Name }}
      </button>
    </mat-dialog-actions>`,
})
export class AlertModalComponent implements OnInit {
  public alertData: AlertDataI;
  public btn1Name!: string;
  public btn2Name!: string;
  constructor(@Inject(MAT_DIALOG_DATA) public data: { data: AlertDataI }) {}

  ngOnInit(): void {
    this.alertData = this.data.data;
    if (this.alertData.md)
      this.alertData.md = marked(this.alertData.md, { async: false });
    this.btn1Name = this.alertData.btn1Name || 'Cancel';
    this.btn2Name = this.alertData.btn2Name || 'Confirm';
  }
}

Usage

import { Component, OnInit } from '@angular/core';
import { AlertModalService } from './alert-modal.service';

@Component({
  selector: 'test-page',
  standalone: true,
  imports: [CommonModule],
  template: ` <button (click)="remove(id)">Delete</button> `,
})
export class TestComponent implements OnInit {
  #alertModalService = inject(AlertModalService);

  async remove(id: number) {
    const isAllow = await this.#alertModalService.open({
      heading: 'Delete',
      body: 'Are you sure you want to delete?',
      // or you can use markdown
      // md: 'Are you sure you want to **delete**?',
      btn1Name: 'Cancel',
      btn2Name: 'Delete',
    });
    // isAllow will be true only if user click on btn2
    if (!isAllow) return;
    // delete
  }
}