0

Hello I have a component that acts as Component Factory for a collection of UI components I have.

in order to show a component from my collection I do like this:

<div myComponentFactory elementType="simpleText" data="my simple text here"></div>

in which my myComponenFactory loads dynamically the requested component (in this example "simpleText" component) and displays it.

the result of the final dom is like this:

<div myComponentFactory>
   <div simpleText>
      my simple text here
   </div>
</div>

however, what I want to achieve is something simpler, such as:

<div myComponentFactory>
   my simple text here
</div>

This is what I'm doing right now. I'm using @ViewChild and loading the requested component inside the template of the factory component:

my-component-factory.component.ts

    @Component({
        selector: '[myComponentFactory]',
        template: '<ng-container #elementToBind></ng-container>',
        encapsulation: ViewEncapsulation.None,
        changeDetection: ChangeDetectionStrategy.OnPush
    })
    export class MyComponentFactoryCompnent implements AfterViewInit {
    
        @Input() elementType: string;
        @Input() data: any;

        @ViewChild('elementToBind', {read: ViewContainerRef}) private elementToBind: ViewContainerRef;

        ngAfterViewInit(): void {

            // switch case with all the components available

            switch (this.elementType) {
                case 'simpleText':
                    // this loads dynamically the "simpleText" component
                    return defer(() => import('path/to/simpleText.module'))
                        .pipe(
                            map((el) => {
                                const module = el.SimpleTextModule;
                                const componentModule = this.compiler.compileModuleAndAllComponentsSync(module);
                                const factory = componentModule.componentFactories.find(c => c.componentType === SimpleTextComponent);
                                return factory;
                            }),
                            map((factory) => {
                                const template: any = this.elementToBind.createComponent(factory);
                                template.instance.data = this.data;
                                return template;
                            })
                        );

                //////////////////////////////////
                // other components switch case //
                //////////////////////////////////
            }
        }
    }

simple-text.component.ts

@Component({
    selector: '[simple-text]',
    templateUrl: './simple-text.component.html',
    encapsulation: ViewEncapsulation.None,
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class SimpleTextComponent{

    @Input() data: any

}

simple-text.component.html

{{data}}

Is it possible to substitute the original host container of my componentFactory? I've tried also creating a directiveFactory instead of a componentFactory, however, the result is the same.

Thanks a lot for your support!!

Marco

MarcoAbi
  • 61
  • 1
  • 6
  • you can use https://angular.io/guide/content-projection – Danail Videv Jan 11 '22 at 17:47
  • I don’t think Content projection may help here. I don’t have a pre-defined content to project inside the component since I have a collection of different components that can dynamically be used. How would you use content projection in my use case? Thanks – MarcoAbi Jan 11 '22 at 18:47

0 Answers0