Angular5:动态组件加载-具有@ angular/core依赖项的StaticInjector错误 [英] Angular5: Dynamic component loading - StaticInjector error with @angular/core dependencies

查看:85
本文介绍了Angular5:动态组件加载-具有@ angular/core依赖项的StaticInjector错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在将电子应用程序从AngularJS迁移到Angular5,并且我遇到的问题是需要加载带有其组件的任意模块并动态地将主要组件呈现给视图(这是一个附加系统). 在我的应用程序中,附加组件是一个angular5模块,其中包含在我的angular5应用程序中呈现的组件.

I am migrating an electron application from AngularJS to Angular5 and I am facing issues in a part where I need to load an arbitrary module with its components and render the main component to the view dynamically (it's an addon system). In my application, an addon is an angular5 module containing a component which is rendered in my angular5 application.

我动态加载这样的组件:

I load dynamically the component like this:

@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()处失败,并出现以下错误:

it works great but when I add Material Component in the template, it fails at factory.create() with this error:

模板:

<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>抛出Error: Template parse errors: 'mat-card' is not a known element...)

The Material modules seems well imported in my addon module else if it's not loaded I have different behaviors: it ignores directives (e.g. <button mat-button></button> is just a <button></button> without material effect and without errors) and material component throw errors (e.g. <mat-card>test<mat-card> throws Error: Template parse errors: 'mat-card' is not a known element...)

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

I have tried to bundle the dynamic module in many different ways: tsc / ngc / ng-packagr / webpack.

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

The bundle is working when I import it normally (static) in the NgModule of another app built with ng-cli.

有人知道如何动态渲染在模板中使用了具有实质性组件/指令的组件吗?

Does someone know how to render dynamically a component which has material component/directive used in the template like fxFlex / mat-button / mat-card ?

我在这里使用SystemJS复制了该错误: https://github .com/thyb/repro-dynamic-loading

I have made a reproduction of the bug with SystemJS here: https://github.com/thyb/repro-dynamic-loading

角度:5.0.2

角材料:5.0.0-rc1

Angular Material: 5.0.0-rc1

推荐答案

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

As @yurzui explained in comments, the @angular/* dependencies were loaded twice. As a workaround, the only way I found to make it work is by using window to share the @angular objects between the application and the addons (@angular/core, @angular/common, @angular/material).

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

in my application 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;
...

这不是很优雅(再见,树摇着),但至少可以奏效...如果有人有一个更简单的解决方案,我会考虑:)

It's not really elegant (bye bye tree shaking) but at least it works... If someone has a simpler solution, I take it :)

我遇到了关于Gitter的关于 @ angular/element 的讨论.似乎很有希望,因为它创建了独立/自包含的Web组件,可以动态注入该组件,而不会遇到我遇到的问题- https ://github.com/angular/angular/pull/19469

I came across a discussion on Gitter about @angular/element which seems promising as it creates standalone/self contained web component which could be injected dynamically without the issues I encountered - https://www.youtube.com/watch?v=ljsOPm4MMEo&feature=youtu.be&t=13m20s. This is a lab project so not available in the current releases but there is already some work on it: https://github.com/angular/angular/pull/19469

这篇关于Angular5:动态组件加载-具有@ angular/core依赖项的StaticInjector错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆