I want to know the correct way to call the greet()
method declared in the host component from a dynamically added component
src/app/app.component.ts
import { Component, ViewChild, ComponentFactoryResolver, ViewContainerRef, } from '@angular/core'; import { OneComponent } from './application/one/one.component'; import { TwoComponent } from './application/two/two.component'; import { ThreeComponent } from './application/three/three.component'; import { AdHostDirective } from './ad-host.directive'; enum Target { ONE = 'one', TWO = 'two', THREE = 'three', } @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'], }) export class AppComponent { @ViewChild(AdHostDirective, { static: true }) adHost: AdHostDirective; constructor(private componentFactoryResolver: ComponentFactoryResolver) {} toggle(target: string): void { let componentFactory: any; switch (target) { case Target.ONE: componentFactory = this.componentFactoryResolver.resolveComponentFactory( OneComponent ); break; case Target.TWO: componentFactory = this.componentFactoryResolver.resolveComponentFactory( TwoComponent ); break; case Target.THREE: componentFactory = this.componentFactoryResolver.resolveComponentFactory( ThreeComponent ); break; default: break; } const viewContainerRef = this.adHost.viewContainerRef; viewContainerRef.clear(); viewContainerRef.createComponent(componentFactory); } greet(): void { alert('Hi'); } }
src/app/ad-host.directive.ts
import { Directive, ViewContainerRef } from '@angular/core'; @Directive({ selector: '[appAddHost]', }) export class AdHostDirective { constructor(public viewContainerRef: ViewContainerRef) {} }
src/app/app.component.html
<button (click)="toggle('one')">One</button> <button (click)="toggle('two')">Two</button> <button (click)="toggle('three')">Three</button> <ng-template appAddHost></ng-template>
In my case there are three components that are dynamically added in all of them I need to call a method in the host component, for example in component One
src/app/application/one/one.component.ts
import { Component, OnInit, Output, EventEmitter } from '@angular/core'; @Component({ selector: 'app-one', templateUrl: './one.component.html', styleUrls: ['./one.component.css'], }) export class OneComponent implements OnInit { constructor() {} ngOnInit(): void {} onClick(): void { // how to call host component greet method? } }
src/app/application/one/one.component.html
<p>one works!</p> <button (click)="onClick()">On click</button>
Update 1
I share the repository of the listed examples to facilitate your collaboration
https://github.com/ilmoralito/add-components-dynamically-demo-app
Thanks for your comments
Advertisement
Answer
You can add an output()
in OneComponent
then you subscribe in your AppComponent
like below:
import { Component, OnInit, Output, EventEmitter } from '@angular/core'; @Component({ selector: 'app-one', templateUrl: './one.component.html', styleUrls: ['./one.component.css'], }) export class OneComponent implements OnInit { @Output() greetEvent: EventEmitter<void> = new EventEmitter<void>(); constructor() {} ngOnInit(): void {} onClick(): void { // how to call host component greet method? this.greetEvent.emit(); } }
src/app/app.component.ts
import { Component, ViewChild, ComponentFactoryResolver, ViewContainerRef, } from '@angular/core'; import { OneComponent } from './application/one/one.component'; import { TwoComponent } from './application/two/two.component'; import { ThreeComponent } from './application/three/three.component'; import { AdHostDirective } from './ad-host.directive'; enum Target { ONE = 'one', TWO = 'two', THREE = 'three', } @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'], }) export class AppComponent { @ViewChild(AdHostDirective, { static: true }) adHost: AdHostDirective; constructor(private componentFactoryResolver: ComponentFactoryResolver) {} toggle(target: string): void { let componentFactory: any; switch (target) { case Target.ONE: componentFactory = this.componentFactoryResolver.resolveComponentFactory( OneComponent ); break; case Target.TWO: componentFactory = this.componentFactoryResolver.resolveComponentFactory( TwoComponent ); break; case Target.THREE: componentFactory = this.componentFactoryResolver.resolveComponentFactory( ThreeComponent ); break; default: break; } const viewContainerRef = this.adHost.viewContainerRef; viewContainerRef.clear(); const componentRef: ComponentRef<any> = viewContainerRef.createComponent(componentFactory); componentRef.instance.greetEvent.subscribe(() => this.greet()); } greet(): void { alert('Hi'); } }