• Stars
    star
    371
  • Rank 110,920 (Top 3 %)
  • Language
    TypeScript
  • License
    MIT License
  • Created almost 4 years ago
  • Updated 5 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

๐Ÿ‘ป A simple to use, highly customizable, and powerful modal for Angular Applications


A simple to use, highly customizable, and powerful modal for Angular Applications

MIT commitizen PRs styled with prettier All Contributors ngneat spectator

Features

โœ… ย TemplateRef/Component Support
โœ… ย Dialog Guards Support
โœ… ย Resizable
โœ… ย Draggable
โœ… ย Multiple Dialogs Support
โœ… ย Customizable

Installation

npm i @ngneat/dialog

Usage

Using a Component

First, create the component to be displayed in the modal:

import { DialogService, DialogRef } from '@ngneat/dialog';

interface Data {
  title: string;
}

@Component({
  template: `
    <h1>{{ title }}</h1>
    <button (click)="ref.close(true)">Close</button>
  `,
  standalone: true,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class HelloWorldComponent {
  ref: DialogRef<Data, boolean> = inject(DialogRef);

  get title() {
    if (!this.ref.data) return 'Hello world';
    return this.ref.data.title;
  }
}

Inside the component, you'll have access to a DialogRef provider. You can call its close() method to close the current modal. You can also pass data that'll be available for any subscribers to afterClosed$.

๐Ÿ’ก Tip

A publicly accessible property of type DialogRef<Input, Output> on your component will be used to infer the input and output types of your component.

Now we can use the DialogService to open the modal and display the component:

import { DialogService } from '@ngneat/dialog';

@Component({
  standalone: true,
  template: ` <button (click)="open()">Open</button> `,
})
export class AppComponent implements OnInit {
  private dialog = inject(DialogService);

  ngOnInit() {
    const dialogRef = this.dialog.open(HelloWorldComponent, {
      // data is typed based on the passed generic
      data: {
        title: '',
      },
    });
  }
}

DialogRef API

The DialogRef instance exposes the following API:

  • afterClosed$ - An observable that emits after the modal closes:
const dialogRef = this.dialog.open(HelloWorldComponent);
dialogRef.afterClosed$.subscribe((result) => {
  console.log(`After dialog has been closed ${result}`);
});
  • backdropClick$ - An observable that emits when the user clicks on the modal backdrop:
const dialogRef = this.dialog.open(HelloWorldComponent);
dialogRef.backdropClick$.subscribe(() => {
  console.log('Backdrop has been clicked');
});
  • resetDrag - A method that can be called to reset the dragged modal to the middle of the screen. An offset can be given as the first parameter to position it different from the center:
dialogRef.resetDrag();
dialogRef.resetDrag({ x: 100, y: 0 });
  • beforeClose - A guard that should return a boolean, an observable, or a promise indicating whether the modal can be closed:
dialogRef.beforeClose((result) => dialogCanBeClosed);
dialogRef.beforeClose((result) => this.service.someMethod(result));
  • ref.data - A reference to the data that is passed by the component opened in the modal:
import { DialogService, DialogRef } from '@ngneat/dialog';

@Component({
  template: `
    <h1>{{ ref.data.title }}</h1>
    <button (click)="ref.close()">Close</button>
  `,
  standalone: true,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class HelloWorldComponent {
  ref: DialogRef<Data> = inject(DialogRef);
}
  • ref.updateConfig - An update function for the config, a common use case would be a reusable component setting its own common properties:
import { DialogService, DialogRef } from '@ngneat/dialog';

@Component({
  template: `
    <h1>{{ ref.data.title }}</h1>
    <button (click)="ref.close()">Close</button>
  `,
  standalone: true,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class MyVeryCommonDialogComponent {
  ref: DialogRef<Data> = inject(DialogRef);

  constructor() {
    this.ref.updateConfig({
      height: '200px',
      width: '400px',
    });
  }
}

You can only update the config before the dialog is opened in the component's constructor.

The library also provides the dialogClose directive helper, that you can use to close the modal:

import { DialogService, DialogCloseDirective } from '@ngneat/dialog';

@Component({
  standalone: true,
  imports: [DialogCloseDirective],
  template: `
    <h1>Hello World</h1>
    <button dialogClose>Close</button>
    <button [dialogClose]="result">Close with result</button>
  `,
})
export class HelloWorldComponent {}

Using a TemplateRef

Sometimes it can be overkill to create a whole component. In these cases, you can pass a reference to an <ng-template>:

import { DialogService } from '@ngneat/dialog';

@Component({
  selector: 'app-root',
  standalone: true,
  template: `
    <ng-template #modalTpl let-ref>
      <h1>Hello World</h1>

      <button (click)="ref.close()">Close</button>
    </ng-template>

    <button (click)="open(modalTpl)">Open</button>
  `,
})
export class AppComponent {
  private dialog = inject(DialogService);

  open(tpl: TemplateRef<any>) {
    this.dialog.open(tpl);
  }
}

Note that in this case, you can access the ref object by using the $implicit context property.

Passing Data to the Modal Component

Sometimes we need to pass data from the opening component to our modal component. In these cases, we can use the data property, and use it to pass any data we need:

import { DialogService } from '@ngneat/dialog';

@Component({
  standalone: true,
  template: ` <button (click)="open()">Open</button> `,
})
export class AppComponent implements OnInit {
  private dialog = inject(DialogService);
  private title = 'Dialog title';

  open() {
    const dialogRef = this.dialog.open(HelloWorldComponent, {
      data: {
        title: this.title,
      },
    });
  }
}

Now we can access it inside our modal component or template, by using the ref.data property.

Dialog Options

Global Options

In the forRoot method when importing the dialog module in the app module you can specify the following options that will be globally applied to all dialog instances.

  • closeButton - Whether to display an 'X' for closing the modal (default is true).
  • enableClose - Whether a click on the backdrop, or press of the escape button, should close the modal (default is true), see enable close.
  • backdrop - Whether to show the backdrop element (default is true).
  • resizable - Whether the modal show be resizeable (default is false).
  • draggable - Whether the modal show be draggable (default is false).
  • draggableConstraint - When draggable true, whether the modal should be constraint to the window. Use none for no constraint, bounce to have the modal bounce after it is released and constrain to constrain while dragging (default is none).
  • size - Set the modal size according to your global custom sizes (default is md).
  • windowClass - Add a custom class to the modal container.
  • width - Set a custom width (default unit is px).
  • minWidth - Set a custom min-width (default unit is px).
  • maxWidth - Set a custom max-width (default unit is px).
  • height - Set a custom height (default unit is px).
  • minHeight - Set a custom min-height (default unit is px).
  • maxHeight - Set a custom max-height (default unit is px).
  • container - A custom element to which we append the modal (default is body).
import { provideDialogConfig } from '@ngneat/dialog';

bootstrapApplication(AppComponent, {
  providers: [
    provideDialogConfig({
      closeButton: boolean,
      enableClose:
        boolean |
        'onlyLastStrategy' |
        {
          escape: boolean | 'onlyLastStrategy',
          backdrop: boolean | 'onlyLastStrategy',
        },
      backdrop: boolean,
      resizable: boolean,
      draggable: boolean,
      draggableConstraint: none | bounce | constrain,
      sizes,
      size: sm | md | lg | fullScreen | string,
      windowClass: string,
      width: string | number,
      minWidth: string | number,
      maxWidth: string | number,
      height: string | number,
      minHeight: string | number,
      maxHeight: string | number,
    }),
  ],
});

Instance Options

For each dialog instance you open you can specify all the global options and also the following 3 options.

  • id - The modal's unique id, the defaults are:
    • If a component is passed - the component's name (e.g. MyCustomDialog).
    • Otherwise, a random id is given.

Note

while not required, it is recommended to set an id in order to prevent unwanted multiple instances of the same dialog.

  • vcr - A custom ViewContainerRef to use.
  • data - A data object that will be passed to the modal template or component.
this.dialog.open(compOrTemplate, {
  //...
  // all global options expect sizes
  //...
  id: string,
  vcr: ViewContainerRef,
  data: {},
});

Enable close

The enableClose property can be configured for each dialog. It can either be an object with the keys escape and backdrop for more granular control, or one of the values described below directly. The latter will apply the set value to both close triggers (escape and backdrop).

If set to true, clicking on the backdrop or pressing the escape key will close the modal. If set to false, this behavior will be disabled.

Additionally, the property can be set to the string value 'onlyLastStrategy'. In this case, the behavior will only apply to the last dialog that was opened, and not to any other dialog. By default, this should be the top-most dialog and behave as true.

Custom Sizes

The default sizes config is:

{
  sizes: {
    sm: {
      height: 'auto',
        width: '400px',
    },
    md: {
      height: 'auto',
        width: '560px',
    },
    lg: {
      height: 'auto',
        width: '800px',
    },
    fullScreen: {
      height: '100%',
        width: '100%',
    },
  }
}

You can override it globally by using the sizes option:

bootstrapApplication(AppComponent, {
  providers: [
    provideDialogConfig({
      sizes: {
        sm: {
          width: 300, // 300px
          minHeight: 250, // 250px
        },
        md: {
          width: '60vw',
          height: '60vh',
        },
        lg: {
          width: '90vw',
          height: '90vh',
        },
        fullScreen: {
          width: '100vw',
          height: '100vh',
        },
      },
    }),
  ],
});

Styling

You can customize the styles with these classes:

ngneat-dialog {
  .ngneat-dialog-backdrop {
    // backdrop styles
    .ngneat-dialog-content {
      // dialog content, where your component/template is placed
      .ngneat-drag-marker {
        // draggable marker
      }
      .ngneat-close-dialog {
        // 'X' icon for closing the dialog
      }
    }
  }
}

More Repositories

1

falso

All the Fake Data for All Your Real Needs ๐Ÿ™‚
TypeScript
3,098
star
2

spectator

๐ŸฆŠ ๐Ÿš€ A Powerful Tool to Simplify Your Angular Tests
TypeScript
2,029
star
3

transloco

๐Ÿš€ ๐Ÿ˜ The internationalization (i18n) library for Angular
TypeScript
1,856
star
4

until-destroy

๐ŸฆŠ RxJS operator that unsubscribe from observables on destroy
TypeScript
1,712
star
5

elf

๐Ÿง™โ€โ™€๏ธ A Reactive Store with Magical Powers
TypeScript
1,527
star
6

content-loader

โšช๏ธ SVG component to create placeholder loading, like Facebook cards loading.
TypeScript
733
star
7

hot-toast

๐Ÿž Smoking hot Notifications for Angular. Lightweight, customizable and beautiful by default.
TypeScript
687
star
8

cashew

๐Ÿฟ A flexible and straightforward library that caches HTTP requests in Angular
TypeScript
671
star
9

reactive-forms

(Angular Reactive) Forms with Benefits ๐Ÿ˜‰
TypeScript
610
star
10

tailwind

๐Ÿ”ฅ A schematic that adds Tailwind CSS to Angular applications
TypeScript
608
star
11

forms-manager

๐Ÿฆ„ The Foundation for Proper Form Management in Angular
TypeScript
517
star
12

query

๐Ÿš€ Powerful asynchronous state management, server-state utilities and data fetching for Angular Applications
TypeScript
510
star
13

error-tailor

๐Ÿฆ„ Making sure your tailor-made error solution is seamless!
TypeScript
478
star
14

helipopper

๐Ÿš A Powerful Tooltip and Popover for Angular Applications
TypeScript
392
star
15

nx-serverless

๐Ÿš€ The Ultimate Monorepo Starter for Node.js Serverless Applications
TypeScript
388
star
16

hotkeys

๐Ÿค– A declarative library for handling hotkeys in Angular applications
TypeScript
325
star
17

edit-in-place

A flexible and unopinionated edit in place library for Angular applications
TypeScript
252
star
18

svg-icon

๐Ÿ‘ป A lightweight library that makes it easier to use SVG icons in your Angular Application
TypeScript
251
star
19

inspector

๐Ÿ•ต๏ธ An angular library that lets you inspect and change Angular component properties
TypeScript
218
star
20

dirty-check-forms

๐ŸฌDetect Unsaved Changes in Angular Forms
TypeScript
199
star
21

input-mask

๐ŸŽญ @ngneat/input-mask is an angular library that creates an input mask
TypeScript
199
star
22

lib

๐Ÿค– Lets you focus on the stuff that matters
TypeScript
180
star
23

transloco-keys-manager

๐Ÿฆ„ The Key to a Better Translation Experience
TypeScript
174
star
24

dag

๐Ÿ  An Angular service for managing directed acyclic graphs
TypeScript
153
star
25

bind-query-params

Sync URL Query Params with Angular Form Controls
TypeScript
147
star
26

from-event

๐ŸฆŠ ViewChild and FromEvent โ€” a Match Made in Angular Heaven
TypeScript
137
star
27

overview

๐Ÿค– A collection of tools to make your Angular views more modular, scalable, and maintainable
TypeScript
104
star
28

aim

Angular Inline Module Schematics
TypeScript
97
star
29

cmdk

Fast, composable, unstyled command menu for Angular. Directly inspired from pacocoursey/cmdk
TypeScript
91
star
30

copy-to-clipboard

โœ‚๏ธ Modern copy to clipboard. No Flash.
TypeScript
78
star
31

variabless

JS & CSS - A Match Made in Heaven ๐Ÿ’Ž
HTML
78
star
32

loadoff

๐Ÿคฏ When it comes to loaders, take a load off your mind...
TypeScript
78
star
33

effects

๐Ÿช„ A framework-agnostic RxJS effects implementation
TypeScript
59
star
34

avvvatars

Beautifully crafted unique avatar placeholder for your next angular project.
TypeScript
42
star
35

react-rxjs

๐Ÿ”Œ "Plug and play" for Observables in React Apps!
TypeScript
37
star
36

subscribe

Subscription Handling Directive
TypeScript
34
star
37

elf-ng-router-store

Bindings to connect Angular router to Elf
TypeScript
24
star
38

ng-standalone-nx

TypeScript
24
star
39

lit-file-generator

๐ŸŽ A lit generator for a component, directive, and controller.
JavaScript
19
star
40

storage

TypeScript
18
star
41

material-schematics

TypeScript
3
star
42

svg-icon-demo

TypeScript
1
star