'Replace deprecated Angular ComponentFactoryResolver, ComponentFactory
I create dynamic components in an HTMLElement with the following code:
import {ApplicationRef, ComponentFactory, ComponentFactoryResolver, ComponentRef, Injector} from '@angular/core';
import {DynamicTableComponent} from '../table/dynamic-table/dynamic-table.component';
export class Table {
private readonly el: Element;
private compRef!: ComponentRef<DynamicTableComponent>;
constructor(el: Element, private resolver: ComponentFactoryResolver, private injector: Injector, private appRef: ApplicationRef) {
this.el = el;
}
public destruct(): void {
if (this.compRef !== null && this.compRef !== undefined) {
this.appRef.detachView(this.compRef.hostView);
// is done by this.compRef.destroy();
// this.compRef.instance.ngOnDestroy();
this.compRef.destroy();
}
}
public addTable(el: Element): void {
const compFactory: ComponentFactory<any> = this.resolver.resolveComponentFactory(DynamicTableComponent);
this.compRef = compFactory.create(this.injector, undefined, el);
this.appRef.attachView(this.compRef.hostView);
}
}
The component is dynamically loaded into an HTML element and added via attachView. The destruct()
method then removes the component cleanly. It´s working fine but since Angular 13 it´s deprecated. So I don´t have an ViewContainerRef and I don´t really know how to do it right in > Angular 13!?
Do you have any advice for me?
Thanks and greetings
Solution 1:[1]
In Angular 13
the new API removes the need for ComponentFactoryResolver being injected into the constructor, like you did in your code.
Now to dynamically create a component you have to use ViewContainerRef.createComponent without using the factory.
So, instead of using
const compFactory: ComponentFactory<any> = this.resolver.resolveComponentFactory(DynamicTableComponent);
you can do:
import {ViewContainerRef} from '@angular/core';
/**
your code logic
*/
constructor(private viewContainerRef: ViewContainerRef)
public addTable(): void {
const component = this.viewContainerRef.createComponent(YourElement);
}
Solution 2:[2]
After spending a few hours I have reached the correct solution for Angular 13 Ivy with the new Update of Component API:
First you need to create a directive, the best would be in a subfolder called 'directives', you can do it manually or use the command:
ng generate directive directives/DynamicChildLoader
This will generate the file:
dynamic-child-loader.directive.ts
There your code will need to be something like:
import { Directive, ViewContainerRef } from '@angular/core';
@Directive({
selector: '[dynamicChildLoader]',
})
export class DynamicChildLoaderDirective {
constructor(public viewContainerRef: ViewContainerRef) {}
}
Now in your component go to the .HTML and you need to include this:
<ng-template dynamicChildLoader=""></ng-template>
And in your .TS:
@ViewChild(DynamicChildLoaderDirective, { static: true })
dynamicChild!: DynamicChildLoaderDirective;
ngOnInit(): void {
this.loadDynamicComponent();
}
private loadDynamicComponent() {
this.dynamicChild.viewContainerRef.createComponent(YourDynamicChildComponent);
}
Don't forget that in your app.module.ts or the module you are using to include in the Declarations part your DynamicChildLoaderDirective
@NgModule({
declarations: [MyExampleComponent, DynamicChildLoaderDirective],
imports: [CommonModule, ComponentsModule],
})
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Elidor00 |
Solution 2 | DylanM |