I have this code in Angular 12 and it works perfectly. The problem comes when changing the version from 12 to 16.
import {
ComponentRef,
ComponentFactoryResolver,
ViewContainerRef,
ViewChild,
Component,
ViewRef
} from "@angular/core";
import { ChildComponent } from "../child/child.component";
@Component({
selector: "app-parent",
templateUrl: "./parent.component.html",
styleUrls: ["./parent.component.css"]
})
export class ParentComponent {
@ViewChild("viewContainerRef", { read: ViewContainerRef })
VCR: ViewContainerRef;
child_unique_key: number = 0;
componentsReferences = Array<ComponentRef<ChildComponent>>()
constructor(private CFR: ComponentFactoryResolver) {}
createComponent() {
let componentFactory = this.CFR.resolveComponentFactory(ChildComponent);
let childComponentRef = this.VCR.createComponent(componentFactory);
let childComponent = childComponentRef.instance;
childComponent.unique_key = ++this.child_unique_key;
childComponent.parentRef = this;
// add reference for newly created component
this.componentsReferences.push(childComponentRef);
}
remove(key: number) {
if (this.VCR.length < 1) return;
let componentRef = this.componentsReferences.filter(
x => x.instance.unique_key == key
)[0];
let vcrIndex: number = this.VCR.indexOf(componentRef as any);
// removing component from container
this.VCR.remove(vcrIndex);
// removing component from the list
this.componentsReferences = this.componentsReferences.filter(
x => x.instance.unique_key !== key
);
}
}
The problem in Angular 16 is that vcrIndex is always -1 when not found.
let vcrIndex: number = this.VCR.indexOf(componentRef as any);
// removing component from container
this.VCR.remove(vcrIndex);
Any suggestions or how can I fix this without having to modify the way dynamic components are created? I have tried several things such as adding an index or an identifier but I still have not been able to solve the problem.
Thx
I have looked to see if the VCR structure is different and I could add an identifier and search for it manually but I couldn't.
Not sure why exactly it worked before, guess it was just a coincidence. this.VCR.indexOf
actually expects ViewRef
and you pass a ComponentRef
there casting it to any
.
The fix is quite simple, you just need to pass componentRef.hostView
to the VCR.indexOf
:
let vcrIndex: number = this.VCR.indexOf(componentRef.hostView);
Here is a working demo using Angular 17.
Just in case, ComponentFactoryResolver
was deprecated long time ago (v13), and you can pass component type directly to the this.VCR.createComponent
:
let childComponentRef = this.VCR.createComponent(ChildComponent);