I am using this technique to dynamically create component:
import { Component, Input, ViewContainerRef, ViewChild, ReflectiveInjector, ComponentFactoryResolver, Output, EventEmitter } from '@angular/core'; @Component({ selector: 'dynamic-component', template: ` <div #dynamicComponentContainer></div> `, }) export default class DynamicLayerComponent { currentComponent = null; @ViewChild('dynamicComponentContainer', { read: ViewContainerRef }) dynamicComponentContainer: ViewContainerRef; @Output() visibility = new EventEmitter<boolean>(); // component: Class for the component you want to create // inputs: An object with key/value pairs mapped to input name/input value @Input() set componentData(data: {component: any, inputs: any }) { console.log('setting'); if (!data) { return; } // Inputs need to be in the following format to be resolved properly let inputProviders = Object.keys(data.inputs).map((inputName) => {return {provide: inputName, useValue: data.inputs[inputName]};}); let resolvedInputs = ReflectiveInjector.resolve(inputProviders); // We create an injector out of the data we want to pass down and this components injector let injector = ReflectiveInjector.fromResolvedProviders(resolvedInputs, this.dynamicComponentContainer.parentInjector); // We create a factory out of the component we want to create let factory = this.resolver.resolveComponentFactory(data.component); // We create the component using the factory and the injector let component = factory.create(injector); // We insert the component into the dom container this.dynamicComponentContainer.insert(component.hostView); // We can destroy the old component is we like by calling destroy if (this.currentComponent) { console.log('fdsafa'); this.currentComponent.destroy(); } this.currentComponent = component; } constructor(private resolver: ComponentFactoryResolver) { console.log('dfsd'); } }
And then I use it like that:
<div *ngFor="let layer of sortedItems" class="single-layer"> <div> <dynamic-component #DynamicLayer [componentData]="{ component: layer.componentClass, inputs: { layerItem: layer, sortFilter: sortFilter } }" (visibility)="setLayerVisibility(layer, $event)"> </dynamic-component> </div>
The problem is that I am not able to bind to an event, it does not work when binding to (visibility). The setLayerVisibility is not called when the event occurs. How to fix that problem ?
Of course my sample component based on componentClass has the @Output set like:
@Output() visibility = new EventEmitter<boolean>(); private visibilityChanged() { this.visibility.emit(this.layerItem.visible); }
Your factory:
factory.create(injector);
will return an ComponentRef object, and with this object you can access that component itself.
You could subscribe to that event via:
component.instance.visibility.subscribe(v => ...);
Just subscribe the output event like this
@ViewChild('yourComponentRef', { read: ViewContainerRef }) container: ViewContainerRef; // Reference for dynamic component private _ref; constructor( private _cfr: ComponentFactoryResolver){ } public addDynamicComponent() { const comp = this._cfr.resolveComponentFactory(<YOUR_DYNAMIC_COMPONENT_HERE>); this._ref = this.container.createComponent(comp); // Input to dynamic component this._ref.instance.inputVarHere = [1, 2, 3]; // Handles output event, just emit your output here this._ref.instance.outputEventHere.subscribe(data => { console.log(data); }); } public removeDynamicComponent() { this._ref.destroy(); }
In your html file
<!-- Section to load dynamic component --> <div #yourComponentRef></div>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With