Skip to content

[Angular Material] Dynamic Dialog Component

Georg Höller
Georg Höller
3 min read
[Angular Material] Dynamic Dialog Component

You know the struggle with angular dialog components when you create mainstream business software. Sometimes I feel like I'm just doing the same for each page again and again. Place a header, some type of grid and finally add all dialogs to it - like "Do you really want to delete it?".

But somehow every dialog is slightly different, so you can't reuse the whole dialog for each grid. Recently I stumbled over 10 of these kinds of components which are all the same but not really. The next thought was - "If we had to change anything around the main content of the dialog we have to change it 10 times".

Could we do better? I think so!
If you are just interested in the source code: Stackblitz

The Only Component We Need


Let us create a new component for our new all-in-one-dialog. Navigate to your preferred location and let the angular CLI work:

ng g c dynamic-dialog


Header over to the TS-File and let us prepare everything for being a dynamic component. For this, you need to inject the MAT_DIALOG_DATA injectionToken to share data with your dialog. Your constructor should look like the following:

constructor(@Inject(MAT_DIALOG_DATA) public data: IDynamicDialogConfig)


For typesafe data transfer between your component I created an interface "IDynamicDialogConfig" which is defined like this:

export interface IDynamicDialogConfig {
  title?: string;
  acceptButtonTitle?: string;
  declineButtonTitle?: string;
  dialogContent: TemplateRef<any>;
}

Properties:
- Title: Defines the Dialogs Title
- TextAcceptButtonTitle: Right-sided Button Text (positive feedback)
- DeclineButtonTitle: Left-sided Button Text (negative feedback)
- DialogContent: The dynamic content we want to display (more later)


Open up the HTML-File and put in your base dialog styling. I go with the angular material default and added the properties above to make everything dynamic:

<h2 mat-dialog-title>{{ data.title }}</h2>
<mat-dialog-content>
  <ng-container [ngTemplateOutlet]="data.dialogContent"> </ng-container>
</mat-dialog-content>
<mat-dialog-actions>
  <button *ngIf="data.declineButtonTitle" mat-button mat-dialog-close>
    {{ data.declineButtonTitle }}
  </button>
  <button mat-button [mat-dialog-close]="true" cdkFocusInitial>
    {{ data.acceptButtonTitle }}
  </button>
</mat-dialog-actions>

That's all for our dynamic dialog component - pretty basic!

Create and showing the dynamic templates


Now navigate to the component where you need to open the dialog and open the HTML-File to create the dynamic templates. You can place them anywhere you want. I normally put them at the bottom. (they don't get rendered)

<!-- Plain Text Example -->
<ng-template #yesNoDialogTemplate>
  <span>Do you really want to delete it?</span>
</ng-template>

<!-- Data Example -->
<ng-template #dataDialogTemplate>
  <span>Count is: {{ count }}</span>
</ng-template>


When you are finished with your templates we have to load them into a TemplateRef variable. We will use ViewChild for this task - head over to your components TS-File:  

@ViewChild('yesNoDialogTemplate') yesNoTemplate: TemplateRef<any> | undefined;  @ViewChild('dataDialogTemplate') dataTemplate: TemplateRef<any> | undefined;

Now all we have to do is to open up our dialogs! For testing purposes I created three buttons, a count variable and three functions:

HTML:

<div style="display: flex; flex-direction: column">
  <button (click)="openYesNoDialog()">Open YesNo Dialog</button>
  <br />
  <button (click)="openDataDialog()">Open Data Dialog</button>
  <button (click)="increaseCount()">Increase Count</button>
</div>

TS:

count: number = 0;

@ViewChild('yesNoDialogTemplate') yesNoTemplate: TemplateRef<any> | undefined;
@ViewChild('dataDialogTemplate') dataTemplate: TemplateRef<any> | undefined;

constructor(public dialog: MatDialog) {}

openYesNoDialog() {
  const dialogRef = this.dialog.open(DynamicDialogComponent, {
    width: '250px',
    data: <IDynamicDialogConfig>{
      title: 'Really?',
      dialogContent: this.yesNoTemplate,
      acceptButtonTitle: 'Delete it!',
      declineButtonTitle: 'No stop!',
    },
  });

  dialogRef.afterClosed().subscribe((result) => {
    if (!result) return;
    // delete it
  });
}

openDataDialog() {
  const dialogRef = this.dialog.open(DynamicDialogComponent, {
    width: '250px',
    data: <IDynamicDialogConfig>{
      title: 'Show the count!',
      dialogContent: this.dataTemplate,
      acceptButtonTitle: 'Ok',
      declineButtonTitle: '',
    },
  });
}

increaseCount() {
  this.count++;
}

As you see in the code above you can give the TemplateRef to your dialog and show it there. This even works with data! Just hit the increaseCount Button and open up the dialog. You will see the updated count in the dialog - awesome!

Running in trouble? Check the source code at Stackblitz

Angular

Comments


Related Posts

Members Public

[ngrok | Angular] External Access to your Local Test Environment

Sometimes you have to test your local hosted API or website with multiple different devices. They may be on the same network and you can open your local ports in some way to get it working but most of the time it's a messy solution. Tech Stack * Angular * ASP.NET

[ngrok | Angular] External Access to your Local Test Environment
Members Public

[Angular | Capacitor] Interact With Your Native Calendar

Recently I had do to implement a simple task: When the user presses the 'save appointment' button, the app should add this event to the native calendar. My first thought was saving an .ical file and open it, till i recognized that this isn't the most user friendly way. After

[Angular | Capacitor] Interact With Your Native Calendar
Members Public

[Angular] Native iOS and Android App - Capacitor

In this blog post we will go through the initial process of how to convert an existing angular project into a cross-platform project. Our focus is on iOS and Android. In addition to this, I show you how to speed up developing and especially testing the app. Setup * Code Editor

[Angular] Native iOS and Android App - Capacitor