How to Create Reusable Dialog in Angular With CDK, Formly and Tailwind

Learn how to create a reusable dialog in Angular using Angular CDK, @ngx-formly, and Tailwind CSS. Follow this step-by-step guide to enhance your Angular application's functionality and maintainability.


As an Angular developer, creating reusable components can significantly improve your productivity and maintainability. Today, I'll walk you through the process of creating a reusable dialog using Angular CDK, @ngx-formly, and Tailwind CSS. We'll build a dialog service that can display forms dynamically, making it a great tool for various use cases in your application. In this guide we will take a look on how to attach a Formly Form inside your dialog for quick-editing your application data.

Introduction to @ngx-formly

@ngx-formly is a dynamic form library for Angular that simplifies the process of creating and managing complex forms. By allowing developers to define form fields as JSON configuration objects, @ngx-formly eliminates the need for repetitive boilerplate code. This results in more maintainable and flexible form structures.

The primary benefit of @ngx-formly is its ability to dynamically render forms based on the configuration provided. This means you can easily create forms that adapt to varying data models and requirements without having to manually code each form field and validation rule. Additionally, @ngx-formly supports integration with popular UI libraries like Angular Material, Bootstrap, and others, making it easy to create consistent and visually appealing forms across your application.

With features like field validation, conditional rendering, and customizable templates, @ngx-formly is an essential tool for Angular developers looking to streamline their form-building processes and enhance their application's flexibility and maintainability.

Prerequisites

Before we start, make sure you have Angular CDK and @ngx-formly installed in your project. If you haven't already set these up, you can follow the instructions below:

  1. Angular CDK: Installation Guide
  2. @ngx-formly: Installation Guide

Step 1: Setting Up Angular CDK and @ngx-formly

First, let's install Angular CDK and @ngx-formly:

npm install @angular/cdk @ngx-formly/core @ngx-formly/material

Step 2: Setting Up Tailwind CSS

If you haven't already set up Tailwind CSS in your Angular project, you can follow the official Tailwind CSS Installation Guide.

Step 3: Creating the Dialog Component

We'll start by creating a standalone dialog component that will be used to display our forms.

ng generate component formly-dialog --standalone

Here’s a basic structure for our FormlyDialogComponent:

import { Component, Inject } from "@angular/core";
import { MAT_DIALOG_DATA, MatDialogRef } from "@angular/material/dialog";
import { FormGroup } from "@angular/forms";
import { FormlyFieldConfig, FormlyFormOptions } from "@ngx-formly/core";

@Component({
  selector: "app-formly-dialog",
  template: `
    <div class="p-6 bg-white rounded-lg">
      <h2 class="text-xl font-bold mb-4">{{ data.title }}</h2>
      <form [formGroup]="form" (ngSubmit)="onSubmit()">
        <formly-form
          [form]="form"
          [fields]="data.fields"
          [model]="model"
          [options]="options"
        ></formly-form>
        <div class="flex justify-end mt-4">
          <button
            type="button"
            class="btn btn-secondary mr-2"
            (click)="onClose()"
          >
            Cancel
          </button>
          <button type="submit" class="btn btn-primary">Submit</button>
        </div>
      </form>
    </div>
  `,
})
export class FormlyDialogComponent {
  form = new FormGroup({});
  model: any = {};
  options: FormlyFormOptions = {};

  constructor(
    public dialogRef: MatDialogRef<FormlyDialogComponent>,
    @Inject(MAT_DIALOG_DATA)
    public data: { title: string; fields: FormlyFieldConfig[] }
  ) {}

  onSubmit() {
    if (this.form.valid) {
      this.dialogRef.close(this.model);
    }
  }

  onClose() {
    this.dialogRef.close();
  }
}

Step 4: Creating the Dialog Service

Next, we'll create a service that will manage opening the dialog with the specified form fields and title.

ng generate service dialog

Here's the implementation of the DialogService:

import { Injectable } from "@angular/core";
import { MatDialog } from "@angular/material/dialog";
import { FormlyFieldConfig } from "@ngx-formly/core";
import { FormlyDialogComponent } from "./formly-dialog/formly-dialog.component";

@Injectable({
  providedIn: "root",
})
export class DialogService {
  constructor(private dialog: MatDialog) {}

  formlyDialog(fields: FormlyFieldConfig[], title: string = "Form") {
    const dialogRef = this.dialog.open(FormlyDialogComponent, {
      width: "400px",
      data: { title, fields },
    });

    return dialogRef.afterClosed();
  }
}

Step 5: Using the Dialog Service

Finally, let's use the DialogService in a component to display a form in a dialog.

import { Component } from "@angular/core";
import { FormlyFieldConfig } from "@ngx-formly/core";
import { DialogService } from "./dialog.service";

@Component({
  selector: "app-root",
  template: `
    <div class="p-6">
      <button class="btn btn-primary" (click)="openDialog()">
        Open Form Dialog
      </button>
    </div>
  `,
})
export class AppComponent {
  constructor(private dialogService: DialogService) {}

  openDialog() {
    const fields: FormlyFieldConfig[] = [
      {
        key: "firstName",
        type: "input",
        templateOptions: {
          label: "First Name",
          placeholder: "Enter your first name",
          required: true,
        },
      },
      {
        key: "lastName",
        type: "input",
        templateOptions: {
          label: "Last Name",
          placeholder: "Enter your last name",
          required: true,
        },
      },
    ];

    this.dialogService
      .formlyDialog(fields, "User Information")
      .subscribe((result) => {
        console.log("Dialog closed with result:", result);
      });
  }
}

Summary

By following the steps above, you've created a reusable dialog component that can be used to display dynamic forms using Angular CDK, @ngx-formly, and Tailwind CSS. This setup not only enhances the reusability of your components but also provides a consistent user experience across your application. You can now expand on this foundation by adding more features and customizations to your custom dialog as needed.

More posts in JavaScript