Reputation: 143
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
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:
MatDialog#open
source code - notice how the types are passed around in the code!MatDialogConfig
source code - notice how the class is defined!Upvotes: 31
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