首页 文章

Angular5:动态组件加载 - 具有@ angular / core依赖关系的StaticInjector错误

提问于
浏览
4

我正在将一个电子应用程序从AngularJS迁移到Angular5,我面临的问题是我需要用其组件加载任意模块并将主要组件动态渲染到视图中(它是一个插件系统) . 在我的应用程序中,一个插件是一个angular5模块,包含一个在angular5应用程序中渲染的组件 .

我像这样动态加载组件:

@ViewChild("view", { read: ViewContainerRef })
view: ViewContainerRef;

constructor(
  // ...
  private compiler: Compiler,
  private injector: Injector,
  private moduleRef: NgModuleRef<any>
) {}

然后,

const addonModule = addonObject.getModule();
this.compiler
  .compileModuleAndAllComponentsAsync(addonModule)
  .then(factories => {
    const factory = factories.componentFactories.find(
      componentFactory =>
        addonObject.getViewComponent().name ==
        componentFactory.componentType.name
    );
    if (factory) {
      const cmpRef = factory.create(this.injector, [], null, this.moduleRef);
      cmpRef.instance.config = {
        from: "afd@test.com",
        apikey: "dsfkjd"
      };
      this.view.insert(cmpRef.hostView);
    }
  });

它工作得很好但是当我在模板中添加Material Component时,它在 factory.create() 处失败并出现此错误:

模板:

<div>
    <button mat-button>test</button>
</div>

错误:

ERROR Error: Uncaught (in promise): Error: StaticInjectorError[Renderer2]: 
  StaticInjectorError[Renderer2]: 
    NullInjectorError: No provider for Renderer2!

要么

模板:

<div fxLayout="row" fxFlex>
    test
</div>

错误:

ERROR Error: Uncaught (in promise): Error: StaticInjectorError[MediaMonitor]: 
  StaticInjectorError[MediaMonitor]: 
    NullInjectorError: No provider for MediaMonitor!

Material模块似乎很好地导入了我的插件模块中,否则如果它没有加载我有不同的行为:它忽略了指令(例如 <button mat-button></button> 只是 <button></button> 没有物质效应且没有错误)和材料组件抛出错误(例如 <mat-card>test<mat-card> throws Error: Template parse errors: 'mat-card' is not a known element...

我试图以多种不同的方式捆绑动态模块:tsc / ngc / ng-packagr / webpack .

当我在使用ng-cli构建的另一个应用程序的NgModule中正常导入(静态)时,该捆绑包正在工作 .

有人知道如何动态渲染模板中使用了材料组件/指令的组件,如fxFlex / mat-button / mat-card?

编辑:我在这里用SystemJS复制了这个bug:https://github.com/thyb/repro-dynamic-loading

角度:5.0.2

角度材料:5.0.0-rc1

1 回答

  • 2

    正如@yurzui在评论中解释的那样,@ angular / *依赖项被加载了两次 . 作为一种解决方法,我发现使其工作的唯一方法是使用 window 在应用程序和插件之间共享@angular对象( @angular/core@angular/common@angular/material ) .

    在我的应用程序index.html中:

    window.angular = {
        core: require("@angular/core"),
        common: require("@angular/common"),
        material: require("@angular/material"),
        ...
    }
    

    在我的插件中:

    const NgModule = (window as any).angular.core.NgModule;
    const CommonModule = (window as any).angular.common.CommonModule;
    const MatButtonModule = (window as any).angular.material.MatButtonModule;
    ...
    

    这不是很优雅(再见树摇晃),但至少它有效...如果有人有一个更简单的解决方案,我接受它:)

    我遇到了关于Gitter关于@angular/element的讨论,这似乎很有希望,因为它创建了独立/自包含的Web组件,可以动态注入而不会遇到我遇到的问题 - https://www.youtube.com/watch?v=ljsOPm4MMEo&feature=youtu.be&t=13m20s . 这是一个实验室项目,因此在当前版本中不可用,但已经有一些工作:https://github.com/angular/angular/pull/19469

相关问题