动态解析注册类型的模块



由于Angular 13.2+弃用ComponentFactoryResolver,我们在如何创建模态方面遇到了问题。由于我们在大型角度应用程序中严重依赖模态,因此我们使用通用服务来创建模态,该服务将创建所需的输入中继到宿主指令,然后宿主指令通过viewContainerRef实例化模态。相关代码如下所示:

// Called by component which wants to show a modal
this.modalService.openModal(
AModalComponent, // ModalComponent to show, can be defined in other module then the calling module
this.componentFactoryResolver,
);
// The host directive then would do the following relevant instantiation:
item.component = viewContainerRef.createComponent(
item.componentFactoryResolver.resolveComponentFactory(item.type), // item.type is the type of AModalComponent
);

现在我们要删除componentFactoryResolver的用法。现在createComponent采用了一个注入器和一个ngModuleRef,这给我们带来了一些问题,我们的方法似乎都不能完全工作。我们这么做的目的:

建议1:调用模式服务时对ngModuleRef进行硬编码:

this.modalService.openModal(
AModalComponent,
this.injector, // injector of calling component
ANgModule // The module declaring AModalComponent, this param would then be relayed to the host directive for instantiation via createNgModuleRef
),

然而,如果调用组件与AModalComponent在同一个模块中(因为两者都是在ANgModule中声明的(并且不起作用,那么这会导致我们的代码中存在循环依赖关系。

建议2:给每个模块一个Id,并在主机组件中进行解析

@NgModule({ // Declare the module with an id
id: 'ANgModuleId',
...
})
export class ANgModule {}
// Use id as param to reference module, does not lead to circular dependencies
this.modalService.openModal(
AModalComponent,
this.injector, // injector of calling component
getNgModuleById('ANgModuleId')) // this param would then be relayed to the host directive for instantiation via createNgModuleRef
)

上面的解决方案没有循环依赖关系,但非常麻烦,因为我们必须为每个模块声明一个id。此外,模态的调用方必须知道他想要实例化的模态的模块的id,这极大地阻碍了易用性。

然而,我们需要ngModuleRef,因为大多数模式都会大量注入依赖项,而没有它"no-injector for…"到处飞。

有人知道您是否可以动态解析声明组件的模块类型吗?这将使我们的实现更加简单,因为宿主指令可以处理所有问题。经过广泛搜索,我没有发现这方面的任何信息。

如果不存在这样的方法,有没有一种更简单的方法可以通过host指令动态创建模态组件?非常感谢您的帮助。

您可以使用以下代码:

of(1)
.pipe(
switchMap(() => {
return import('@modules/a-ng.Module ');
}),
switchMap((impInstance: any) => {
const component = impInstance['AModalComponent'];
const componentRef = parent.createComponent<AModalComponent>(component);
return of({ componentRef });
})
).subscribe(({ componentRef}) => {
const self = componentRef.instance as AModalComponent;
self.message='test';
});