Paula
Paula

Reputation: 143

Angular material dialog - pass types into dialog component

I'm working on data driven app and currently I'm facing a problem of passing types into material angular dialog. I want to create reusable dialog form and need to change types for new dialog instance.

Is there a way to pass type into material dialog or into component? Or maybe there is possibility to create types in dialog itself from string passed as data?

I want to use types in dialog component like this (or similar):

export class DialogDynamicItemManagerDialog<T> {

    public dialogName: string;
    public items: Array<T>;
    public selectedItem: T;
    ...
}

I've tried to pass the type like this:

 OpenDynamicDialog(): void {
    this.dialog.open(DialogDynamicItemManagerDialog<MyType>, {
      data: {
        title: 'Manage items',
        items: this.items
      },
    });
}

but obviously it doesn't work.

I've also tried this:

 OpenDynamicDialog(): void {
    const dialogRef = this.dialog.open(DialogDynamicItemManagerDialog, {
      data: {
        title: 'Manage items',
        items: this.items,
        itemType: itemType
      },
    });
}

but I haven't find a way to change string into type in dialog afterwards.

Upvotes: 12

Views: 11539

Answers (2)

Edric
Edric

Reputation: 26750

TL;DR:

You can use the following code to specify the type that your dialog's data will use:

import { MatDialog } from '@angular/material/dialog';

export class MyComponent {
  constructor(private dialog: MatDialog) { }

  openDialog() {
    this.dialog.open<MyDialogComponent, MyType>(MyDialogComponent, {
      data: {
        // Your data goes here
      }
    };
  }
}

In your dialog component:

import { MAT_DIALOG_DATA } from '@angular/material/dialog';

export class MyDialogComponent {
  constructor(@Inject(MAT_DIALOG_DATA) public data: MyType) { }
}

The open method of the MatDialog class actually allows three types to be specified (in order of sequence):

  • T: The component class (optional - although there's no default value, you don't have to specify it if you're just calling the method without any other types)
  • D: The type to be used for the data to be added to the dialog (optional - defaults to any)
  • R: The type to be used for the result of the dialog (optional - defaults to any)

The method is defined as below:

  /**
   * Opens a modal dialog containing the given component.
   * @param componentOrTemplateRef Type of the component to load into the dialog,
   *     or a TemplateRef to instantiate as the dialog content.
   * @param config Extra configuration options.
   * @returns Reference to the newly-opened dialog.
   */
  open<T, D = any, R = any>(componentOrTemplateRef: ComponentType<T> | TemplateRef<T>,
          config?: MatDialogConfig<D>): MatDialogRef<T, R> {
    // ...
  }

The D type is then passed to MatDialogConfig, which accepts the same type to be used for the data to be passed in to the dialog.


References:

Upvotes: 31

Ranil Wijeyratne
Ranil Wijeyratne

Reputation: 777

I don't think it's possible to have a typed dialog the way you outlined it. But what you can do is something like:

export class MyDialog {

    private savedForLater: SomeType;

    constructor(
            public containingDialog: MatDialogRef<MyDialog>,
            @Inject(MAT_DIALOG_DATA) public data: SomeType) {

        this.savedForLater = data;
    }

}

Unfortunately when you launch the dialog the type isn't enforced so you could still do this

const dialogData = {} as SomeType
const fakeDialogData = {} as SomeOtherType
this.dialog.open(MyDialog, { data: dialogData });
this.dialog.open(MyDialog, { data: fakeDialogData }); // this compiles

Upvotes: 1

Related Questions