'How do you get the module of a component that's been dynamically loaded in Angular v13?

In v12 you could use the following code to load/import a component dynamically, access its NgModule through ComponentFactory and then add it to the DOM using ViewContainerRef.

const injector: Injector = /* injected */
const cfg: ComponentFactoryResolver = /* injected */
const module = await import('path/to/component/file');
const componentDef = module['MyComponent'];
const cf: ComponentFactory = cfg.resolveComponentFactory(componentDef);
const compModule: NgModuleRef = (cf as any).ngModule;

const container: ViewContainerRef = /*retrieved using @ViewChild*/
container.createComponent(cf, null, injector, compModule)

As of v13 ComponentFactory (docs) and ComponentFactoryResolver (docs) are now labeled as deprecated and a new signature has been added to ViewContainerRef.createComponent which accepts a componentType: Type<C> as the first argument.

abstract createComponent<C>(componentType: Type<C>, options?: { index?: number; injector?: Injector; ngModuleRef?: NgModuleRef<unknown>; projectableNodes?: Node[][]; }): ComponentRef<C>

So you would now do the following to add a dynamically loaded component to the DOM.

const module = await import('path/to/component/file');
const componentDef = module['MyComponent'];

const container: ViewContainerRef = /*retrieved using @ViewChild*/
container.createComponent(componentDef)

However, the docs for the new signature of ViewContainerRef.createcomponent show the 2nd optional argument is an object called options that has an optional property ngModuleRef:NgModuleRef<unknown>. For which the docs state:

ngModuleRef: an NgModuleRef of the component's NgModule, you should almost always provide this to ensure that all expected providers are available for the component instantiation.

Question

I've struggled to find any example usage of ViewContainerRef.createcomponent that actually includes a value for ngModuleRef and with the deprecation of ComponentFactoryResolver and ComponentFactory am wondering what the correct/official way to retrieve the module in which the component is declared?

Edit

Just to clarify, i'm interested in whether it's still possible to retrieve the module of a component that's been dynamically loaded using the new method in Angular v13, without explicitly knowing the type of that module?



Solution 1:[1]

In Angular 13+, the solution is to create without using the DEPRECATED compiler.

without using the factory, you have to use ViewContainerRef.createComponent.

Import injector in constructor constructor(private _injector: Injector) {} create module reference using NgModuleRef(ngModule,parentInjector)

const moduleRef: NgModuleRef<T> = createNgModuleRef(module, this._injector);
this.viewRef.createComponent(componentToOpen, {ngModuleRef: moduleRef});

You can also read about all deprecations and possible replacements in the Angular doc https://angular.io/guide/deprecations

Solution 2:[2]

As i'm using single component angular modules (SCAMs) i also have access to the components module when the component file is loaded.

I'm using a naming convention of MyComponent whose module is named MyComponentModule so am able to access both the component Class and components NgModule Class using the component name. The NgModule Class can then be passed to createNgModuleRef to create the instance of NgModuleRef required for the createComponent method.

import {createNgModuleRef} from '@angular/core';

const injector: Injector = /* injected */
const compName = 'MyComponent';
const module = await import('path/to/component/file');
const componentClass = module[compName];
const ngModuleRef = createNgModuleRef(module[`${compName}Module`], injector);

const container: ViewContainerRef = /*retrieved using @ViewChild*/
container.createComponent(componentClass, {injector:injector, ngModuleRef:ngModuleRef})

However, this has the drawback of having to have direct access to the components module type, which is not ideal.

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 Siva Gokul
Solution 2