In creating dynamic components in Angular 2, I found out that this process requires ViewContainerRef
in order to add newly created component to DOM.
And in passing @Input
and @Output
to those dynamically created components, I found the answer in the second link above and here.
However, if I were to create a service named shape.service
that contains functions returning different shape components with some @Input
like bgColor
, I don't know how this service will create a component without specifying DOM location, and how the container-component receives this returned component (probably its type will be ComponentRef
) from the service and injects it to the DOM container-component specifies.
For example, a service contains a method:
getCircle(bgColor:string): ComponentRef<Circle> {
let circleFactory = componentFactoryResolver.resolveComponentFactory(CircleComponent);
let circleCompRef = this.viewContainerRef.createComponent(circleFactory);
circleCompRef.instance.bgColor = bgColor;
return circleCompRef;
}
First question rises here, how do I make this.viewContainerRef
point to no where for the meantime? The reason why I'm importing ViewContainerRef
is to create component dynamically.
Second question is after container-component receives input-specificcomponentRef
from the service, how will it inject to its DOM?
UPDATE: I think my question above wasn't specific enough. I'm in a situation where:
@Input
, That means the service calling component has no idea where those componentRef will get injected. In short, I need independent component objects that can be injected to anywhere, anytime I want.
I'm reading the rumTimeCompiler solution several times already but I don't really get how that really works. It seems like there's too much work compared to component creation using viewContainerRef. I'll dig into that more if I find no other solution...
Maybe this plunker will help you: https://plnkr.co/edit/iTG7Ysjuv7oiDozuXwj6?p=preview
As far as i know, you will need the ViewContainerRef
inside of your service.
But the component calling your service can add it as an parameter, like this:
(just a the service.. see plunker for full working example)
import { Injectable, ViewContainerRef, ReflectiveInjector, ComponentFactoryResolver, ComponentRef } from '@angular/core';
import { HelloComponent, HelloModel } from './hello.component';
@Injectable()
export class DynamicCompService {
constructor (private componentFactoryResolver: ComponentFactoryResolver) { }
public createHelloComp (vCref: ViewContainerRef, modelInput: HelloModel): ComponentRef {
let factory = this.componentFactoryResolver.resolveComponentFactory(HelloComponent);
// 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);
// add inputs first !! otherwise component/template crashes ..
comp.instance.model = modelInput;
// all inputs set? add it to the DOM ..
vCref.insert(comp.hostView);
return comp;
}
}