Angular Create multiple components using ComponentFactoryResolver

313 Views Asked by At

I'm trying to create components dynamically using the ComponentFactoryResolver.

I have a component that has an @input that holds the component ref and the component inputs.

the problem is when the components are created in the DOM they hold the exact instance data.

is it possible to create the components without them holding the instance state by reference?

class TrimItemsToPopupListComponent implements OnInit, OnDestroy, AfterViewInit {
    @Input() component?: {
        ref: ComponentType<unknown>,
        inputs: Record<string, unknown>[]
    };
    constructor(
        private resolver: ComponentFactoryResolver,
        private cd: ChangeDetectorRef
    ) {}
        ngAfterViewInit(): void {
        this.componentVC.clear();
        this.inputItems.slice(0, this.trimCount).forEach(() => {
            const factory = this.resolver.resolveComponentFactory(this.component.ref);
            const componentRef = this.componentVC.createComponent(factory);

            this.component.inputs.forEach((cmpInput, index) => {
                const inputKey = Object.keys(cmpInput)[0] as string;

                // @ts-ignore
                componentRef.instance[inputKey] = this.component.inputs[index][inputKey];
            });
        });
        this.cd.detectChanges();
    }

1

There are 1 best solutions below

0
On

You could try this:

class TrimItemsToPopupListComponent implements OnInit, OnDestroy, AfterViewInit {
    @Input() component ?: {
    ref: ComponentType<unknown>,
        inputs: Record<string, unknown>[]
    };
constructor(
        private resolver: ComponentFactoryResolver,
        private cd: ChangeDetectorRef
    ) { }
ngAfterViewInit(): void
{
    this.componentVC.clear();
    this.inputItems.slice(0, this.trimCount).forEach(() => {
        const factory = this.resolver.resolveComponentFactory(this.component.ref);

        this.component.inputs.forEach((cmpInput, index) => {
            const inputKey = Object.keys(cmpInput)[0] as string;
            const inputValue = this.component.inputs[index][inputKey];
            const inputBinding = { [inputKey]: inputValue };

        // Pass the input binding as the `inputs` property
        const componentRef = this.componentVC.createComponent(factory, undefined, undefined, [inputBinding]);
        });
    });
    this.cd.detectChanges();
}

Brief explanation:

  • The ComponentFactoryResolver is used to resolve a ComponentFactory for the component specified in the component.ref input property.
  • The inputItems array is sliced to a smaller size using the trimCount property, and a loop is performed for each item in the sliced array.
  • Within the loop, the inputs property of the component input is iterated over, and an input binding is created for each input using the inputKey and inputValue variables.
  • The createComponent() method of the ViewContainerRef is then called, passing the ComponentFactory, as well as the input binding created in the previous step, using the inputs property.

This should create multiple instances of the component, each with its own set of input bindings, rather than sharing the same instance data by reference.