50

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);
  }
1
  • Problem still exists? Commented Feb 16, 2017 at 7:16

2 Answers 2

49

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 => ...);
Sign up to request clarification or add additional context in comments.

5 Comments

cannot subscribe of undefined. Maybe related to lifecyclehooks of component generation?
answer to self: it does. Just, in the function body of the subscribe do a {outputs.emit(v)} and in the function that also gets the inputs, also pass the outputs from the invoking component
@yogibimbi Can you elaborate your answer a bit, I am getting cannot subscribe of undefined whenever I am trying to give output. I load dynamic component from directive .
show us your code, best would be a small stackblitz.com
//this worked for me :) component.instance.visibility.subscribe(v => ...);
25

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>

1 Comment

where we have subscribe means which lifecycle hook will called

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.