I'm submitting a ... (check one with "x")
[ ] bug report => search github for a similar issue or PR before submitting
[ x ] feature request
[ ] support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question
Current behavior
None
Expected/desired behavior
A directive that is able to create components dynamically, the same way as NgTemplateOutlet created embedded view dynamically.
Pros
- Remove the boilerplate in a component. Developer does not need to query (
ViewChild) and manually create the component. (ComponentFactoryResolver, ViewContainerRef)
- Expressed in the template.
- Simple
- Aligned with NgTemplateOutlet, same idea same concept
Cons
- Host attribute bindings are not expressed in a template. Not much of a con, as its expected and
ComponentRef can be used to set values on the instance...
- Getting a reference to the returned
ComponentRef is via callback only.
- more ?
Directive
@Directive({
selector: '[swapCmp]'
})
export class SwapComponentDirective {
private component: any;
constructor(private cfr: ComponentFactoryResolver,
private vcRef: ViewContainerRef,
private tRef: TemplateRef<Object>) {
}
@Input() swapCmpBindings: ResolvedReflectiveProvider[];
@Input() swapCmpInjector: Injector;
@Input() swapCmpProjectables: any[][];
@Output() onCreate: EventEmitter<ComponentRef<any>> = new EventEmitter<ComponentRef<any>>(false);
@Input() set swapCmp(component: any) {
this.component = component;
this.vcRef.clear();
if (this.component) {
let injector = this.swapCmpInjector || this.vcRef.parentInjector;
if (Array.isArray(this.swapCmpBindings) && this.swapCmpBindings.length > 0) {
injector = ReflectiveInjector.fromResolvedProviders(this.swapCmpBindings, injector);
}
const cmpRef = this.vcRef.createComponent(
this.cfr.resolveComponentFactory(component),
this.vcRef.length,
injector,
this.swapCmpProjectables
);
cmpRef.changeDetectorRef.detectChanges();
this.onCreate.emit(cmpRef);
}
}
}
<template [swapCmp]="ctx.component" [swapCmpBindings]="ctx.bindings" [swapCmpInjector]="ctx.injector" [swapCmpProjectables]="ctx.projectableNodes"></template>
The name here is SwapComponent but it just as an example, took it from my code base
- A Developer provides a component, changing the component will re-create.
- Injector is optional, if not supplied the current injector is used.
- Bindings are used to allow additional providers to the injector (something like
viewProviders)
- In case
ng-content is needed the developer can supply projectableNodes.
What do you think?
I'm submitting a ... (check one with "x")
Current behavior
None
Expected/desired behavior
A directive that is able to create components dynamically, the same way as
NgTemplateOutletcreated embedded view dynamically.Pros
ViewChild) and manually create the component. (ComponentFactoryResolver,ViewContainerRef)Cons
ComponentRefcan be used to set values on the instance...ComponentRefis via callback only.Directive
viewProviders)ng-contentis needed the developer can supply projectableNodes.What do you think?