Angular v14.1 added a new function named createComponent
. This function can cover the use-cases where the ComponentFactory
symbol was previously used.
The function allows creating a ComponentRef
instance based on provided Component
and a set of options:
import { ApplicationRef, createComponent, EnvironmentInjector } from '@angular/core';
@Injectable({ providedIn: 'root' })
export class ToastService {
constructor(
private appRef: ApplicationRef,
private injector: EnvironmentInjector
) { }
open(text: string) {
// Create a `ComponentRef` instance.
const dialogRef = createComponent(ToastComponent, {
environmentInjector: this.injector
});
dialogRef.setInput('text', text);
document.body.appendChild(dialogRef.location.nativeElement);
// Register the newly created ref using the `ApplicationRef` instance
// to include the component view into change detection cycles.
this.appRef.attachView(dialogRef.hostView);
}
}
It’s possible to pass a new environment injector inherited from the current one:
export class ToastService {
constructor(
private appRef: ApplicationRef,
private injector: EnvironmentInjector
) { }
open(text: string) {
const newEnvInjector = createEnvironmentInjector([
{
provide: 'MyToken',
useValue: 'Token'
}
], this.injector);
const dialogRef = createComponent(ToastComponent, {
environmentInjector: newEnvInjector
});
dialogRef.setInput('text', text);
document.body.appendChild(dialogRef.location.nativeElement);
this.appRef.attachView(dialogRef.hostView);
}
}
It’s possible to pass an element injector:
export class ToastService {
constructor(
private appRef: ApplicationRef,
private injector: EnvironmentInjector
) { }
open(text: string) {
const elementInjector = Injector.create({
providers: [
{
provide: 'MyToken',
useValue: 'Token'
}
],
});
const dialogRef = createComponent(ToastComponent, {
environmentInjector: this.injector,
elementInjector
});
dialogRef.setInput('text', text);
document.body.appendChild(dialogRef.location.nativeElement);
this.appRef.attachView(dialogRef.hostView);
}
}
The component can be appended to a host
element:
export class ToastService {
constructor(
private appRef: ApplicationRef,
private injector: EnvironmentInjector
) { }
open(text: string) {
const dialogRef = createComponent(ToastComponent, {
environmentInjector: this.injector,
hostElement: document.getElementById('toasts-container')!
});
dialogRef.setInput('text', text);
this.appRef.attachView(dialogRef.hostView);
}
}
We can pass projectableNodes
— A list of DOM nodes that should be projected through <ng-content>
of the new component instance:
openDialog<T>(dialogContent: Type<T>) {
const footer = document.createElement('p');
footer.innerText = 'footer';
const dialogContentRef = createComponent(dialogContent, {
environmentInjector: this.injector
})
const dialogRef = createComponent(DialogComponent, {
environmentInjector: this.injector,
hostElement: document.getElementById('dialog-container')!,
projectableNodes: [
// ng-content nodes
[dialogContentRef.location.nativeElement],
// second ng-content (e.g <ng-content select="footer"></ng-content>)
[ footer ]
]
})
this.appRef.attachView(dialogRef.hostView)
}
The createComponent
API can be used to create components outside components and directives.