I am trying to create a component with a dynamic child Component as given in this example: Angular Dynamic Component Loader. Well, it is kind easy, and I have implemented it. In my current case, I am trying to load a component dynamically in MatDialog class. Reference: Angular Material Dialog. So far, so good. My Dynamic Component Class:
@Component({
selector: 'dynamic-dialog',
template: `<div class="ad-banner">
<h3>{{title}}</h3>
<ng-template dialog-host></ng-template>
</div>`
})
export class DialogComponent<T>
{
@ViewChild(DialogDirective) dialogHost: DialogDirective;
title:string;
constructor(
public dialogRef: MatDialogRef<T>, @Inject(MAT_DIALOG_DATA) public
data: any, component:T,
private _toast: Toaster, private apiBase: apiBase, type: { new():
T;},
private componentFactoryResolver: ComponentFactoryResolver
){
let componentFactory = this.componentFactoryResolver.resolveComponentFactory<Component>(type);
let viewContainerRef = this.dialogHost.viewContainerRef;
viewContainerRef.clear();
let componentRef = viewContainerRef.createComponent(componentFactory);
this.title = data.title;
}
}
My Dialog Service:
openGenericDialog<T>(t:T, data:{},
type: { new(): T ;},
height:string,
width:string,
callback
): MatDialogRef<DialogComponent<T>> {
let dialogRef = this.dialog.open(DialogComponent, {
width: width,
height:height,
data: data
});
dialogRef.afterClosed().subscribe(result => {
//when you close the box, it will return the control right here
if(callback){
callback(result);
}
//write the closed event right here.
});
return dialogRef;
}
Now, it is obvious that if we load any component dynamically in a dialog, it will have a button to close the dialog. Now, I understand that I can use EventEmitter for this to close it. I declare an event emitter, and then try to create an event handler at my generic class. But that will require me to write an OutPut event in each component I may be showing inside that dialog box. Is there a way, where I can directly capture the event in child class? I am not really good with Angular yet, so unable to find the correct way to describe or implement this. All I want is a function, which I can call inside my ChildComponent which will call the close function in the dialog service. Is that intuitive enough? If not, please let me know so I can add more detail. Sorry if it is confusing. Please note that above is not a compilable code and is still WIP, it has been posted here just for the reference to show what I am trying to do.
Update: I fixed it using the injected service. Earlier, I was not comfortable injecting a service because there can be multiple dialogs, one on top of another which could have messed up the references of the active dialogbox. So I did a simple workaround and added a dictionary with a key which will contain the reference of the dialogbox. This way, I will be able to control the dialogboxes using a particular key. Following are the changes I did:
Dialog Service:
@Injectable()
export class DialogService{
dialogs:any={};
constructor(public dialog: MatDialog) {}
Storing a reference in the dictionary:
openGenericDialog<T>(t:T, data:{},
type: { new(): T ;},
height:string,
width:string,
key:string, <=== added a unique key to be associated with the dialog
callback
): MatDialogRef<DialogComponent<T>> {
let dialogRef = this.dialog.open(DialogComponent, {
width: width,
height:height,
data: data
});
//add it in the dictionary
this.dialogs[key] = dialogRef; <== storing the object in a dictionary using the unique key.
dialogRef.afterClosed().subscribe(result => {
//when you close the box, it will return the control right here
//remove from the dialog collection
if(this.dialogs[key]){
this.dialogs[key] = '';
}
if(callback){
callback(result);
}
//write the closed event right here.
});
return dialogRef;
}
Closing the box:
closeDialog(key:string, data:any){
let dialogRef = this.dialogs[key];
if(dialogRef){
dialogRef.close(data);
}
}
Sweet! Thanks for the help :)