Jase
Jase

Reputation: 91

How to render and load dynamically a component with Angular 9 (Ivy)

I used to load and render my components by its name with a service using ComponentFactoryResolver.

This is a part of the code, the one which renders the component

//Get the Type of the component by its string's name
        const type: Type<any> = await this.getTypeOfComponent(component);
        

        //Call the factory for create the component
        const componentFactory = this.componentFactoryResolver.resolveComponentFactory(type);
        const componentRef = componentFactory.create(new DialogInjector(this.injector, data));
        this.appRef.attachView(componentRef.hostView);

        //Attach the component 
        const domElem = (componentRef.hostView as EmbeddedViewRef<any>).rootNodes[0] as HTMLElement;
        document.querySelector('.flyout').firstChild.appendChild(domElem);

        this.dialogComponentRef = componentRef;

        return homeRef;

And I got the Type of the component using two lines in the function getTypeOfComponent:

let factories = Array.from(this.componentFactoryResolver['_factories'].values());
let factoryClass: any = factories.find((x: any) => x.componentType.name === component);

return factoryClass.componentType;

I've read in Angular 9 with Ivy, you have to import the component for 'lazy loading' and render a component.

Using for example

this.foo = import(`./foo/foo.component`)
                       .then(({ FooComponent }) => FooComponent);

But I'm unable of doing this, I'm always getting the same error which is

core.js:5845 ERROR Error: Uncaught (in promise): Error: Cannot find module 'details-products/details-products.component' Error: Cannot find module 'details-products/details-products.component'

I've tried with a lot of paths to the component and still getting the same error.

Any ideas? Any other ways of rendering a component in Angular 9 with Ivy?

EDIT:

I've tried an import like the blogs said. For example:

import('src/app/my-component.ts')

That'll work for me, BUT if I do the next:

let src = 'src/app/my-component.ts';
import(src); 

Then this won't work and throws the error of can't find the module.

Any ideas?

Upvotes: 2

Views: 2317

Answers (2)

Shreyas Kene
Shreyas Kene

Reputation: 1

I solved my problem using this way.

const factories = Array.from(this.resolver['ngModule'].instance.constructor.ɵmod.declarations);
const factoryClass = <Type<any>>factories.find((x: any) => x.name === 'your_component_name');

Upvotes: 0

Jo&#227;o Marlon
Jo&#227;o Marlon

Reputation: 11

I solved my problem with a ugly way. But I believe that will helps you until find a better solution:

const object = Array.from(this.componentFactoryResolver['ngModule'].instance.constructor.decorators.values())[0]['args'][0];
const factories = object.declarations.concat(object.entryComponents, object.imports, object.providers);

// const factories = Array.from(this.componentFactoryResolver['_factories'].keys());
const factoryClass = < Type<any> > factories.find((x: any) => x.name === your_component_name);
const factory = this.componentFactoryResolver.resolveComponentFactory(factoryClass);
//
const ref = this.dialogService.open(factory.componentType, {
  header: your_component_name,
});

Upvotes: 1

Related Questions