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

Thi*_*ult 5 angular-material2 angular

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

我像这样动态加载组件:

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

constructor(
  // ...
  private compiler: Compiler,
  private injector: Injector,
  private moduleRef: NgModuleRef<any>
) {}
Run Code Online (Sandbox Code Playgroud)

然后,

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

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

模板:

<div>
    <button mat-button>test</button>
</div>
Run Code Online (Sandbox Code Playgroud)

错误:

ERROR Error: Uncaught (in promise): Error: StaticInjectorError[Renderer2]: 
  StaticInjectorError[Renderer2]: 
    NullInjectorError: No provider for Renderer2!
Run Code Online (Sandbox Code Playgroud)

或者

模板:

ERROR Error: Uncaught (in promise): Error: StaticInjectorError[Renderer2]: 
  StaticInjectorError[Renderer2]: 
    NullInjectorError: No provider for Renderer2!
Run Code Online (Sandbox Code Playgroud)

错误:

ERROR Error: Uncaught (in promise): Error: StaticInjectorError[MediaMonitor]: 
  StaticInjectorError[MediaMonitor]: 
    NullInjectorError: No provider for MediaMonitor!
Run Code Online (Sandbox Code Playgroud)

材料模块似乎很好地导入到我的插件模块中,否则如果它没有加载我有不同的行为:它忽略指令(例如<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 复制了这个错误:https : //github.com/thyb/repro-dynamic-loading

角度:5.0.2

角材质:5.0.0-rc1

Thi*_*ult 2

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

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

window.angular = {
    core: require("@angular/core"),
    common: require("@angular/common"),
    material: require("@angular/material"),
    ...
}
Run Code Online (Sandbox Code Playgroud)

在我的插件中:

const NgModule = (window as any).angular.core.NgModule;
const CommonModule = (window as any).angular.common.CommonModule;
const MatButtonModule = (window as any).angular.material.MatButtonModule;
...
Run Code Online (Sandbox Code Playgroud)

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

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