I\'m looking for a way to instantiate a component in Angular2 from within the code of another component. Unlike the many people that have asked a similar question I\'m not so mu
There seems to be a (new?) API function for doing what is described in mxii's answer. The ViewContainerRef has the createComponent
method. It instantiates the component and adds it to the view.
let factory = this._cmpFctryRslvr.resolveComponentFactory(AnyComponent);
let cmp = this.viewContainer.createComponent(factory);
cmp.instance.name = 'peter';
In case if anyone wants to avoid any statement in accepted answer here is the snippet
public createComponent<T>(vCref: ViewContainerRef, type: Type<T>): ComponentRef<T> {
let factory = this._cmpFctryRslvr.resolveComponentFactory(type);
// vCref is needed cause of that injector..
let injector = ReflectiveInjector.fromResolvedProviders([], vCref.parentInjector);
// create component without adding it directly to the DOM
let comp = factory.create(injector);
return comp;
}
Here's a working demo: https://plnkr.co/edit/pgkgYEwSwft3bLEW95Ta?p=preview
import {Component, NgModule, ViewChild, ElementRef, Input, Output, EventEmitter, ViewContainerRef, ComponentRef, ComponentFactoryResolver, ReflectiveInjector} from '@angular/core'
import {BrowserModule} from '@angular/platform-browser'
@Component({
selector: 'any-comp',
template: '<div (click)="clicked.emit($event)">here i am.. {{name}}</div>'
})
export class AnyComponent {
@Input() name;
@Output() clicked = new EventEmitter();
constructor() {
console.log('some1 created me.. ! :)');
}
}
@Component({
selector: 'my-app',
template: `
<div>
<h2>Hello {{name}}</h2>
<template #placeHolder>
</template>
</div>
`,
})
export class App {
@ViewChild('placeHolder', {read: ViewContainerRef}) private _placeHolder: ElementRef;
name:string;
constructor(private _cmpFctryRslvr: ComponentFactoryResolver) {
this.name = 'Angular2'
}
ngOnInit() {
let cmp = this.createComponent(this._placeHolder, AnyComponent);
// set inputs..
cmp.instance.name = 'peter';
// set outputs..
cmp.instance.clicked.subscribe(event => console.log(`clicked: ${event}`));
// all inputs/outputs set? add it to the DOM ..
this._placeHolder.insert(cmp.hostView);
}
public createComponent (vCref: ViewContainerRef, type: any): ComponentRef {
let factory = this._cmpFctryRslvr.resolveComponentFactory(type);
// vCref is needed cause of that injector..
let injector = ReflectiveInjector.fromResolvedProviders([], vCref.parentInjector);
// create component without adding it directly to the DOM
let comp = factory.create(injector);
return comp;
}
}
@NgModule({
imports: [ BrowserModule ],
declarations: [ App, AnyComponent ], // ! IMPORTANT
entryComponents: [ AnyComponent ], // ! IMPORTANT --> would be lost due to Treeshaking..
bootstrap: [ App ]
})
export class AppModule {}
You can place your child component inside parent component.
<parent-component>
<child-component></child-component>
</parent-component>
The child component exposes an EventEmitter property with which it emits events when something happens. The parent binds to that event property and reacts to those events. https://angular.io/docs/ts/latest/cookbook/component-communication.html