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

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


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.


I found the following code to generate components on the fly from a string (angular2 generate component from just a string) and created a compileBoundHtml directive from it that passes along input data (doesn't handle outputs but I think the same strategy would apply so you could modify this):

    @Directive({selector: '[compileBoundHtml]', exportAs: 'compileBoundHtmlDirective'})export class CompileBoundHtmlDirective {    // input must be same as selector so it can be named as property on the DOM element it's on    @Input() compileBoundHtml: string;    @Input() inputs?: {[x: string]: any};    // keep reference to temp component (created below) so it can be garbage collected    protected cmpRef: ComponentRef<any>;    constructor( private vc: ViewContainerRef,                private compiler: Compiler,                private injector: Injector,                private m: NgModuleRef<any>) {        this.cmpRef = undefined;    }    /**     * Compile new temporary component using input string as template,     * and then insert adjacently into directive's viewContainerRef     */    ngOnChanges() {        class TmpClass {            [x: string]: any;        }        // create component and module temps        const tmpCmp = Component({template: this.compileBoundHtml})(TmpClass);        // note: switch to using annotations here so coverage sees this function        @NgModule({imports: [/*your modules that have directives/components on them need to be passed here, potential for circular references unfortunately*/], declarations: [tmpCmp]})        class TmpModule {};        this.compiler.compileModuleAndAllComponentsAsync(TmpModule)          .then((factories) => {            // create and insert component (from the only compiled component factory) into the container view            const f = factories.componentFactories[0];            this.cmpRef = f.create(this.injector, [], null, this.m);            Object.assign(this.cmpRef.instance, this.inputs);            this.vc.insert(this.cmpRef.hostView);          });    }    /**     * Destroy temporary component when directive is destroyed     */    ngOnDestroy() {      if (this.cmpRef) {        this.cmpRef.destroy();      }    }}

The important modification is in the addition of:

Object.assign(this.cmpRef.instance, this.inputs);

Basically, it copies the values you want to be on the new component into the tmp component class so that they can be used in the generated components.

It would be used like:

<div [compileBoundHtml]="someContentThatHasComponentHtmlInIt" [inputs]="{anInput: anInputValue}"></div>

Hopefully this saves someone the massive amount of Googling I had to do.


createSub() {  const factory = this.resolver.resolveComponentFactory(SubComponent);  const ref = this.location.createComponent(factory, this.location.length,   ref.instance.model = {Which you like to send}  ref.instance.outPut = (data) =>{ //will get called from from SubComponent}   this.location.parentInjector, []);  ref.changeDetectorRef.detectChanges();return ref;}SubComponent{ public model; public outPut = <any>{};   constructor(){ console.log("Your input will be seen here",this.model) } sendDataOnClick(){    this.outPut(inputData) }    }