Создание динамических компонентов в Angular
Angular v14.1 добавил новую функцию createComponent. Эта функция может заменить заменяет ComponentFactory, который использовался в предыдущих версиях. Функция позволяет создавать экземпляр ComponentRef на основе предоставленного компонента и набора параметров:
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);
}
}Можно передать новый environment injector, унаследованный от текущего:
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);
}
}Так же можно создать 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);
}
}Компонент может быть добавлен к элементу-хосту:
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);
}
}Мы можем передать projectableNodes — список узлов DOM, которые должны быть проецированы через <ng-content> нового экземпляра компонента:
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)
}Метод createComponent в Angular используется для динамического создания экземпляров компонентов во время выполнения приложения. Это полезно, например, для создания модальных окон, динамической загрузки данных или интеграции с библиотеками сторонних разработчиков.