Update to this in this new question.
I have followed this guide which I found by finding this question but then being pointed to this question as a fix for some of the issues that occurred in the prior question. The first link code example allows me to dynamically add and remove multiple instances of a particular child component that appear within a parent component.
This works great and I’ve more or less copied the code in that example into mine with the only difference being that the examples ParentComponent I’ve called LiveSummaryComponent
(which is a page) and the examples ChildComponent I’ve called StatusBoxComponent
.
In the example code there is a button residing on the ParentComponent (LiveSummaryComponent)
that calls the createComponent()
when clicked, that deals with creating instances of the ChildComponent (StatusBoxComponent)
. This works, however want I would like to do is to be able to have a button on a separate non related component to the ParentComponent (LiveSummaryComponent)
that calls the ParentComponent (LiveSummaryComponent) createComponent()
function instead. This separate component is actually a modal dialog pop up box, which I’ve named AddStatusBoxComponent
.
In order to do this, I’ve copied how the example codes ChildComponent (StatusBoxComponent)
does it, since this calls the remove()
function that resides in the ParentComponent (LiveSummaryComponent)
to remove an instance of itself (the ChildComponent (StatusBoxComponent)) from the ParentComponent (LiveSummaryComponent)
page.
My StatusBoxComponent is as follows:
html template:
<button (click)="remove_me()">I am a Child {{unique_key}}, click to Remove</button>
ts file:
import { Component} from '@angular/core';
import { LiveSummaryComponent } from 'src/app/pages/live-summary/live-summary.component';
@Component({
selector: 'app-status-box',
templateUrl: './status-box.component.html',
styleUrls: ['./status-box.component.css']
})
export class StatusBoxComponent implements OnInit
{
public unique_key!: number;
public parentRef!: LiveSummaryComponent;
constructor() {}
remove_me()
{
console.log(this.unique_key)
this.parentRef.remove(this.unique_key)
}
}
The ParentComponent (LiveSummaryComponent) is as follows:
html template:
<button type="button" (click)="createComponent()">
I am Parent, Click to create Child
</button>
<ng-template #viewContainerRef></ng-template>
ts file:
import { Component, OnInit, ComponentRef, ComponentFactoryResolver, ViewContainerRef, ViewChild, ViewRef} from '@angular/core';
import { StatusBoxComponent } from '../../components/status-box/status-box.component';
@Component({
selector: 'app-live-summary',
templateUrl: './live-summary.component.html',
styleUrls: ['./live-summary.component.css']
})
export class LiveSummaryComponent implements OnInit
{
@ViewChild("viewContainerRef", { read: ViewContainerRef })
VCR!: ViewContainerRef;
child_unique_key: number = 0;
componentsReferences = Array<ComponentRef<StatusBoxComponent>>()
createComponent() {
let componentFactory = this.CFR.resolveComponentFactory(StatusBoxComponent);
let childComponentRef = this.VCR.createComponent(componentFactory);
let childComponent = childComponentRef.instance;
childComponent.unique_key = ++this.child_unique_key;
childComponent.parentRef = this;
// add reference for newly created component
this.componentsReferences.push(childComponentRef);
}
remove(key: number)
{
if (this.VCR.length < 1) return;
let componentRef = this.componentsReferences.filter(
x => x.instance.unique_key == key
)[0];
let vcrIndex: number = this.VCR.indexOf(componentRef.hostView);
// removing component from container
this.VCR.remove(vcrIndex);
// removing component from the list
this.componentsReferences = this.componentsReferences.filter(
x => x.instance.unique_key !== key
);
}
}
In the AddStatusBoxComponent
modal dialog I’ve followed the same pattern as to how the ChildComponent (StatusBoxComponent)
calls the ParentComponent (LiveSummaryComponent) remove()
function which definitely works. But when I attempt to execute calling the ParentComponent (LiveSummaryComponent) remove()
function by submitting the button in the AddStatusBoxComponent
modal dialog I get the following error in the browser console:
ERROR TypeError: Cannot read properties of undefined (reading 'createComponent')
at AddStatusBoxComponent.addStatusBox (add-status-box.component.ts:133:25)
at AddStatusBoxComponent_Template_form_ngSubmit_3_listener (add-status-box.component.html:4:54)
at executeListenerWithErrorHandling (core.js:15285:1)
at Object.wrapListenerIn_markDirtyAndPreventDefault [as next] (core.js:15323:1)
at SafeSubscriber.__tryOrUnsub (Subscriber.js:183:1)
at SafeSubscriber.next (Subscriber.js:122:1)
at Subscriber._next (Subscriber.js:72:1)
at Subscriber.next (Subscriber.js:49:1)
at EventEmitter_.next (Subject.js:39:1)
at EventEmitter_.emit (core.js:25944:1)
The AddStatusBoxComponent Modal Dialog code is as follows:
html template:
<form [formGroup]="AddStatusBoxForm" (ngSubmit)='addStatusBox()'>
<button class='green-button' type="submit">Add</button>
</form>
Note, I’m hiding most of the other parts of the form for simplicity, but there is a reason I’m using the formGroup and ngSubmit for the button.
ts file:
import { Component} from '@angular/core';
import { FormBuilder } from '@angular/forms';
import { MatDialogRef } from '@angular/material/dialog';
import { LiveSummaryComponent } from 'src/app/pages/live-summary/live-summary.component';
@Component({
selector: 'app-add-status-box',
templateUrl: './add-status-box.component.html',
styleUrls: ['./add-status-box.component.css']
})
export class AddStatusBoxComponent
{
public parentRef!: LiveSummaryComponent;
constructor(private form: FormBuilder, private dialogRef: MatDialogRef<AddStatusBoxComponent>) {}
addStatusBox()
{
this.parentRef.createComponent();
this.dialogRef.close();
}
}
Essentially I’m trying to create instances of StatusBoxComponent
in a different unrelated modal dialog component that calls the createComponent()
function that is defined in the ParentComponent (LiveSummaryComponent)
but I can’t seem to get it to work.
You could use a Service
to achieve the communication of the event instead of trying to use the createComponent
method that's inside the component directly.
See this StackBlitz demo.
Note that this is in Angular v14, so I had to comment out a line regarding the dynamic component creation.
Also, I am not using an actual modal. But if you adjust the code, this should work in your case in exactly the same way.