Skip to content

Instantly share code, notes, and snippets.

@mfp22
Last active February 28, 2024 21:26
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mfp22/479a6860510286e69d9cb7ea3a448d5e to your computer and use it in GitHub Desktop.
Save mfp22/479a6860510286e69d9cb7ea3a448d5e to your computer and use it in GitHub Desktop.
import {
Component,
Input,
OnChanges,
SimpleChanges,
OnDestroy,
} from '@angular/core';
import {
MatDialogRef,
MatDialogConfig,
MatDialog,
} from '@angular/material/dialog';
import { Observable } from 'rxjs';
// Separate files
export interface AppDialogState {
[index: string]: Observable<any>;
}
export interface AppDialogActions {
[index: string]: Function;
}
@Component({
selector: 'app-dialog-content-component',
template: '',
})
export class DialogContentComponent {
state: AppDialogState;
actions: AppDialogActions;
}
@Component({
selector: 'app-dialog',
template: '',
})
export class AppDialogComponent
implements OnChanges, OnDestroy, DialogContentComponent {
// Can't find a type that this.dialog.open likes without importing something obscure
@Input() component: any;
@Input() state: AppDialogState = {};
@Input() actions: AppDialogActions = {};
@Input() open = false;
@Input() config: MatDialogConfig;
dialogRef: MatDialogRef<any>;
constructor(public dialog: MatDialog) {}
ngOnChanges(changes: SimpleChanges) {
if (changes.open) {
this.applyDialogState(changes.open.currentValue);
}
}
ngOnDestroy() {
// setTimeout because applyDialogState is sometimes on a timeout
// when this runs and can reopen the dialog
// after this component is already destroyed.
setTimeout(() => this.closeDialog());
}
applyDialogState = (shouldBeOpen: boolean) => {
setTimeout(() => {
// Change detection console error without this
const isOpen = !!this.dialogRef;
if (!isOpen && shouldBeOpen) {
this.openDialog();
} else if (isOpen && !shouldBeOpen) {
this.closeDialog();
}
});
};
openDialog() {
this.dialogRef = this.dialog.open(this.component, this.config);
this.dialogRef.componentInstance.state = this.state;
this.dialogRef.componentInstance.actions = this.actions;
}
closeDialog() {
if (this.dialogRef) {
this.dialogRef.close();
}
this.dialogRef = undefined;
}
}
@donbabbeo
Copy link

Can i ask you a simple usage explanation, please?

When i write imperatively i can do something like this:
dialog.open(TestComponent)
where TestComponent is not an instance but it's used as a type.

How can i do the same with this dialog?
If i understand it correctly i should do something along this:
<app-dialog [component]="TestComponent" ...></app-dialog>
but it complains that TestComponent is not a property of the component, while if i try to add a property it obviously fails at runtime because the instance is undefined.

What i'm doing wrong?

@donbabbeo
Copy link

Obviously the problem was on my side...
Didn't think of referencing an ng-template.
It works flawlessly now!

Just for the sake of clarity, if anyone is dumb enough to be in my same shoes, it's used like this:

<app-dialog [component]="dialogComponent" [open]="open$ | async"></app-dialog>

<ng-template #dialogComponent> ... something ... </ng-template>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment