Handle @Input and @Output for dynamically created Component in Angular 2

thpnk picture thpnk · Nov 2, 2016 · Viewed 10.2k times · Source

How to handle/provide @Input and @Output properties for dynamically created Components in Angular 2?

The idea is to dynamically create (in this case) the SubComponent when the createSub method is called. Forks fine, but how do I provide data for the @Input properties in the SubComponent. Also, how to handle/subscribe to the @Output events the SubComponent provides?

Example: (Both components are in the same NgModule)

AppComponent

@Component({
  selector: 'app-root'
})  
export class AppComponent {

  someData: 'asdfasf'

  constructor(private resolver: ComponentFactoryResolver, private location: ViewContainerRef) { }

  createSub() {
    const factory = this.resolver.resolveComponentFactory(SubComponent);
    const ref = this.location.createComponent(factory, this.location.length, this.location.parentInjector, []);
    ref.changeDetectorRef.detectChanges();
    return ref;
  }

  onClick() {
    // do something
  }
}

SubComponent

@Component({
  selector: 'app-sub'
})
export class SubComponent {
  @Input('data') someData: string;
  @Output('onClick') onClick = new EventEmitter();
}

Answer

Ante Jablan Adamović picture Ante Jablan Adamović · Oct 12, 2017

You can easily bind it when you create the component:

createSub() {
    const factory = this.resolver.resolveComponentFactory(SubComponent);
    const ref = this.location.createComponent(factory, this.location.length, this.location.parentInjector, []);
    ref.someData = { data: '123' }; // send data to input
    ref.onClick.subscribe( // subscribe to event emitter
      (event: any) => {
        console.log('click');
      }
    )
    ref.changeDetectorRef.detectChanges();
    return ref;
  }

Sending data is really straigthforward, just do ref.someData = data where data is the data you wish to send.

Getting data from output is also very easy, since it's an EventEmitter you can simply subscribe to it and the clojure you pass in will execute whenever you emit() a value from the component.