Angular 2 Dynamically insert a component into a specific DOM node without using ViewContainerRef
When creating a component you can pass the DOM node that will act as a host element of the created component:
create(injector: Injector, projectableNodes?: any[][], rootSelectorOrNode?: string|any, ngModule?: NgModuleRef): ComponentRef
But since this component is not child of any other component, you have to manually attach it to ApplicationRef so you get change detection.
So here is what you need to do:
1) Create a component specifying the root node under which it should be added.
2) Attach the view to the ApplicationRef so that you get change detection. You will still have no Input
and ngOnChanges
operations, but the DOM update will be working fine.
@Component({
template: `
<div id="container">
<h1>My Component</h1>
</div>
`,
selector: 'my-app'
})
export class AppComponent {
constructor(private resolver: ComponentFactoryResolver,
private injector: Injector,
private app: ApplicationRef) {
}
addDynamicComponent() {
let factory = this.resolver.resolveComponentFactory(SimpleComponent);
let newNode = document.createElement('div');
newNode.id = 'placeholder';
document.getElementById('container').appendChild(newNode);
const ref = factory.create(this.injector, [], newNode);
this.app.attachView(ref.hostView);
}
}
You should never modify DOM outside Angular because it will lead to unpredictable behavior. Even if you append <simple-cmp>
element manually it means nothing because it's not processed by Angular. All changes to DOM inside Angular app have to go through Angular methods.
Dynamically create a new component:
@Component({
selector: 'my-component',
template: '<div #element></div>',
})
export class MyComponent {
@ViewChild('element', {read: ViewContainerRef}) private anchor: ViewContainerRef;
constructor(private resolver: ComponentFactoryResolver) { }
whatever() {
let factory = this.resolver.resolveComponentFactory(ChildComponent);
this.anchor.createComponent(factory);
}
}