Angular. Вставить компонент в body
Функциональность требуется для диалогов, уведомлений и других элементов наложения. Данная реализация манипулирует только одним компонентом в один момент времени. Позволяет вставить компонент с нужными Input()
ами.
Вариант добавления вручную
@Injectable({
providedIn: 'root',
})
export class DomService {
/** ref to window document */
private readonly document: Document;
/** renderer instance */
private readonly renderer: Renderer2;
/** attached component */
private componentRef: ComponentRef<unknown>;
constructor(
@Inject(DOCUMENT) document,
private componentFactoryResolver: ComponentFactoryResolver,
private injector: Injector,
private applicationRef: ApplicationRef,
rendererFactory: RendererFactory2
) {
this.renderer = rendererFactory.createRenderer(null, null);
this.document = document;
}
attachComponent<T>(component: Type<T>, componentProps: object = null): T {
const componentRef = this.componentFactoryResolver
.resolveComponentFactory(component)
.create(this.injector);
if (componentProps !== null && typeof componentRef.instance === 'object') {
Object.assign(componentRef.instance, componentProps);
}
// put inside the angular component tree
this.applicationRef.attachView(componentRef.hostView);
const componentRootNode = (componentRef.hostView as EmbeddedViewRef<
unknown
>).rootNodes[0] as HTMLElement;
// append component to the body
this.renderer.appendChild(this.document.body, componentRootNode);
this.componentRef = componentRef;
return componentRef.instance;
}
/**
* Destroy component
*/
removeComponent(): void {
this.applicationRef.detachView(this.componentRef.hostView);
this.componentRef.destroy();
}
}
Вариант добавления с помощью CDK Portal
@Injectable({
providedIn: 'root',
})
export class CdkDomService {
/** ref to window document slot */
private bodyPortalOutlet: DomPortalOutlet;
constructor(
@Inject(DOCUMENT) document,
componentFactoryResolver: ComponentFactoryResolver,
injector: Injector,
applicationRef: ApplicationRef
) {
this.bodyPortalOutlet = new DomPortalOutlet(
document.body,
componentFactoryResolver,
applicationRef,
injector
);
}
attachComponent<T>(component: ComponentType<T>, componentProps: object = null): T {
const componentPortal = new ComponentPortal<T>(component);
const componentRef = this.bodyPortalOutlet.attach<T>(componentPortal);
if (componentProps !== null && typeof componentRef.instance === 'object') {
Object.assign(componentRef.instance, componentProps);
}
return componentRef.instance;
}
/**
* Destroy component
*/
removeComponent(): void {
this.bodyPortalOutlet.detach();
}
}