0

Link to updated question.

I posted this question before. To briefly summarise; I’m trying to call a function that creates instances of a component using the ComponentFactoryResolver and ViewContainerRef inside of another function that is in a non related component. For specifics refer to the previous question.

However, since then I’ve made a bit of progress and have pinpointed the issue. I’ve changed the AddStatusBoxComponent ts file (the component I’m trying to call the other components function from) from this:

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();
  }
}

to this:

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(public parentRef: LiveSummaryComponent, private form: FormBuilder, private dialogRef: MatDialogRef<AddStatusBoxComponent>) {}

  addStatusBox()
  {
    this.parentRef.createComponent();
    this.dialogRef.close();
  }
}

where I’ve injected the LiveSummaryComponent into the constructor and added it to the providers in app.module.ts instead. With this I’m able to call the LiveSummaryComponent createComponent() function, and it works because I tested it by commenting out everything in that function and putting a simple console.log() to confirm it works.

However when I uncomment the normal contents of the createComponent() function and call it from the AddStatusBoxComponent it now gives me a different error message in the browser console:

ERROR TypeError: Cannot read properties of undefined (reading 'createComponent')
    at LiveSummaryComponent.createComponent (live-summary.component.ts:52:38)
    at AddStatusBoxComponent.addStatusBox (add-status-box.component.ts:129:20)
    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)

This indicates that it’s line 52 in the LiveSummaryComponent which is this line that resides in the createComponent() function:

let childComponentRef = this.VCR.createComponent(componentFactory);

this.VCR is a ViewContainerRef

that is defined as:

@ViewChild("viewContainerRef", { read: ViewContainerRef })
public VCR!: ViewContainerRef;

I’ve had to use ! Else I get this error:

Property 'VCR' has no initializer and is not definitely assigned in the constructor.

The @ViewChild I think comes from this in the LiveSummaryComponent template file:

<button type="button" (click)="createComponent()">
   I am Parent, Click to create Child
</button>
<ng-template #viewContainerRef></ng-template>

I know it might be confusing that both the LiveSummaryComponent createComponent() function has the same name as the this.VCR.createComponent(componentFactory); But they are different functions.

So I think the issue lies here, but I have no idea how to resolve it, so that I’m able to execute the LiveSummaryComponent createComponent() function inside the AddStatusBoxComponent addStatusBox() function at the click of a button.

The full code can be found in the previous question, with the only difference this time being my changes to how the LiveSummaryComponent is referenced in the AddStatusBoxComponent via dependency injection in the constructor.

I'm still new to Angular so lot of this I don't really understand properly.

Summary of what I want to achieve:

What I'm trying to achieve is to create instances of a child component (StatusBoxComponent) within a parent (LiveSummaryComponent) but the function createComponent() that creates instances of StatusBoxComponent that resides in LiveSummaryComponent is called from a completely different component (AddStatusBoxComponent) which pops up as a modal dialogue when a button is pressed on a HeaderCaomponent But I can't access the LiveSummaryComponent createComponent() function from the AddStatusBoxComponent due the error I highlighted in the question

SneakyShrike
  • 723
  • 1
  • 10
  • 31

2 Answers2

1

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.

Vasileios Kagklis
  • 784
  • 1
  • 4
  • 14
  • That worked nicely, i also tried it in the removeComponent function in a different component, although I couldn't figure out how to pass parameters to functions from different component via a service. – SneakyShrike Oct 14 '22 at 19:04
0

If you want to create a child component in a parent by taking an action; I would use a combination of ngif and maybe ngfor if you can add an infinite amount of children (like messages board or to-do lists).

Your createComponent function will only be a trigger for the component to display. Example:

ts:

this.displayPopUp = false;
// ...
constructChild = () => {
   this.displayPopUp = true;
} 

html:

<button (click)="constructChild">click me</button>
<app-some-child *ngIf="displayPopUp"></app-some-child>

Is that what you try to achieve?

mikegross
  • 1,674
  • 2
  • 12
  • 27
  • What I'm trying to achieve is to create instances of a child component (StatusBoxComponent) within a parent (LiveSummaryComponent) but the function createComponent() that creates instances of StatusBoxComponent that resides in LiveSummaryComponent is called from a completely different component (AddStatusBoxComponent) which pops up as a modal dialogue when a button is pressed on a HeaderCaomponent But I can't access the LiveSummaryComponent createComponent() function from the AddStatusBoxComponent due the error I highlighted in the question – SneakyShrike Oct 02 '22 at 10:22
  • 1
    You do not need to access this function. You have to setup a service that shares some value between the component giving the order and the one receiving the order. Then react on the order being triggered. – mikegross Oct 03 '22 at 14:08
  • I couldn't get it to work, I have this:
    in the LiveSummaryComponennt html where test is either true or false. That I've just set in the same component for now. When I set it to true it just creates instances of the StatusBoxCoomponent infinity and errors my program.
    – SneakyShrike Oct 07 '22 at 08:44
  • if you check my last question: https://stackoverflow.com/questions/73830955/angular-a-function-defined-in-one-component-that-generates-dynamic-child-comp it might give you give you a bit more idea of what I'm trying to do. I'm using the ComponentRef, ComponentFactoryResolver and ViewContainerRef to dynamically add and remove multiple instances of a particular child component that appear within a parent component. I followed this code: https://stackblitz.com/edit/add-or-remove-dynamic-component-npaetz?file=src%2Fapp%2Fparent%2Fparent.component.ts, – SneakyShrike Oct 07 '22 at 08:49
  • I want to be able to do what the example code does, but create instances of those child components from a button click inside the separate modal dialogue component, instead of the button being in the same component, as where the createComponent() is defined. – SneakyShrike Oct 07 '22 at 08:53