如何获取 Angular v13 中动态加载的组件的模块?

jam*_*mes 5 angular angular13

在 v12 中,您可以使用以下代码动态加载/导入组件,通过访问它NgModule,ComponentFactory然后使用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)
Run Code Online (Sandbox Code Playgroud)

从 v13 开始,ComponentFactory( docs ) 和ComponentFactoryResolver( docs ) 现在被标记为已弃用,并且添加了一个新签名ViewContainerRef.createComponent,该签名接受 acomponentType: Type<C>作为第一个参数。

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

因此,您现在可以执行以下操作来将动态加载的组件添加到 DOM。

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

const container: ViewContainerRef = /*retrieved using @ViewChild*/
container.createComponent(componentDef)
Run Code Online (Sandbox Code Playgroud)

但是,新签名的文档ViewContainerRef.createcomponent显示第二个可选参数是一个名为 的对象options,具有可选属性ngModuleRef:NgModuleRef<unknown>。文档指出:

ngModuleRef:组件的 NgModule 的 NgModuleRef,您几乎应该始终提供它以确保所有预期的提供程序均可用于组件实例化。

问题

我一直在努力寻找任何ViewContainerRef.createcomponent实际包含ngModuleRef和 的值的示例用法ComponentFactoryResolver,并且ComponentFactory我想知道检索声明组件的模块的正确/官方方法是什么?

编辑

只是为了澄清,我感兴趣的是是否仍然可以检索使用 Angular v13 中的新方法动态加载的组件的模块,而无需明确知道该模块的类型?

小智 7

在 Angular 13+ 中,解决方案是在不使用已弃用的编译器的情况下进行创建。

不使用工厂,就必须使用ViewContainerRef.createComponent.

在构造函数中导入注入器 constructor(private _injector: Injector) {} 创建模块引用使用NgModuleRef(ngModule,parentInjector)

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

您还可以在 Angular 文档中阅读有关所有弃用和可能的替换的信息https://angular.io/guide/deprecations

编辑 2023 年 4 月 19 日:

由于createNgModuleRefAngular 13 已弃用,createNgModule因此您应该使用:

const moduleRef: NgModuleRef<T> = createNgModule(module, this._injector);
this.viewRef.createComponent(componentToOpen, {ngModuleRef: moduleRef});
Run Code Online (Sandbox Code Playgroud)


jam*_*mes 0

由于我使用的是单组件角度模块(SCAM),因此在加载组件文件时我还可以访问组件模块。

MyComponent我正在使用其模块命名的命名约定MyComponentModule,因此我能够使用组件名称访问组件类和组件 NgModule 类。然后可以传递 NgModule 类来创建该方法所需的createNgModuleRef实例。NgModuleRefcreateComponent

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})
Run Code Online (Sandbox Code Playgroud)

然而,这样做的缺点是必须直接访问组件模块类型,这并不理想。