通过自定义注入器将服务注入动态生成的组件时,Angular ChangeDetection 不起作用

Posted

技术标签:

【中文标题】通过自定义注入器将服务注入动态生成的组件时,Angular ChangeDetection 不起作用【英文标题】:Angular ChangeDetection not working when injecting services via custom injector into dynamically generated components 【发布时间】:2021-10-08 22:32:15 【问题描述】:

由于我没有找到任何答案或类似案例,所以我在这里发布这个问题。

我的应用具有以下结构:

应用模块 布局模块 主要组件 侧边栏组件 SidebarService providedIn: 'root' 内容模块 内容组件 ContentService providedIn: 'ContentModule' ContentSidebarComponent 另一个模块 另一个组件 AnotherService providedIn: 'AnotherModule' 另一个边栏组件

ContentModule 和 AnotherModule 风格的模块还有很多。

SidebarComponent 内部是一个用于动态组件生成的视图容器。

SidebarService 包含一个类似 generateSidebar(component: any): void 的方法,它在 ContentComponent:generateSidebar(ContentSidebarComponent) 和 AnotherComponent:generateSidebar(AnotherSidebarComponent) 内部调用,并像这样处理动态组件加载:

带有自定义注入器的动态组件加载器

const componentFactory = this.componentFactoryResolver.resolveComponentFactory(...);

const viewContainerRef = viewContainer.viewContainerRef;
viewContainerRef.clear();

let componentRef: ComponentRef<any>;
let injector: Injector|undefined = undefined;

injector = Injector.create(
  providers: [
    
      provide: ContentService,     //AnotherService respectively
      useClass: ContentService,    //AnotherService respectively
      deps: []
    
  ]
)

componentRef = viewContainerRef.createComponent(
  componentFactory,
  0,
  injector
);

没有像“No provider for ...”这样的错误。

访问 ContentComponent 时,会在 SidebarComponent 内部正常生成 ContentSidebarComponent。

访问AnotherComponent时,在SidebarComponeent内部正常生成AnotherSidebarComponent。

问题 ContentService 也在 ContentComponent 内部使用,并且 ContentService 的一些属性发生了变化。似乎 ChangeDetection 在 ContentSidebarComponent 中不起作用,因为 ContentService 的属性在那里没有改变。

顺便说一句:如果有多个实例,两个服务都会抛出错误。所以这不是这种情况,也不是问题。

当注入服务的属性值发生变化时,如何在动态生成的组件内触发 ChangeDetection?

提前致谢。

【问题讨论】:

您确定问题出在变更检测上吗?添加一个按钮以将您认为已更改的值记录到控制台,并查看它是否真的发生了变化。 我在服务中添加了一个属性,可以通过一个按钮进行更改。按钮,它的点击方法在 ContentComponent 中。服务中的属性会发生变化,就像在 ContentComponent 的模板中一样,但在 ContentSidebarComponent 的模板中没有 好吧...好像有2个实例,构造函数被触发了两次...如何避免这种情况?如何注入服务? angular.io/guide/… 似乎使用 useExisting 而不是 useClass 是解决方案......但这给了我对 ContentService 的循环依赖 【参考方案1】:

修复了它像这样将服务实例传递给提供者

public generateComponent(component: any, service: any, instance: any) 
  const componentFactory = this.componentFactoryResolver.resolveComponentFactory(component);

  const viewContainerRef = viewContainer.viewContainerRef;
  viewContainerRef.clear();

  let componentRef: ComponentRef<any>;
  let injector: Injector|undefined = undefined;

  injector = Injector.create(
    providers: [
      
        provide: service,
        useValue: instance,
        deps: []
      
    ]
  )

  componentRef = viewContainerRef.createComponent(
    componentFactory,
    0,
    injector
  );

【讨论】:

以上是关于通过自定义注入器将服务注入动态生成的组件时,Angular ChangeDetection 不起作用的主要内容,如果未能解决你的问题,请参考以下文章

Angular 2 - 如何将依赖项注入到自定义类中,该类不是组件并且不作为服务公开

如何定义注入动态组件的位置?

Android 组件化路由组件 ( 页面跳转参数依赖注入 )

.NET Core反射获取带有自定义特性的类,通过依赖注入根据Attribute元数据信息调用对应的方法

如何使用服务的输入/输出动态创建组件实例并将其分别注入 DOM?

注入默认字体