【发布时间】:2018-04-30 18:06:52
【问题描述】:
我正在将电子应用程序从 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);
}
});
效果很好,但是当我在模板中添加材质组件时,它在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> 抛出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
【问题讨论】:
-
你能设置复制吗?
-
@yurzui 是的,github.com/thyb/repro-dynamic-loading
-
感谢转载。您遇到的问题与您的应用程序加载两个
core.umd.js文件的事实有关。当 Angular 解决依赖关系时,它将 ElementRef 类存储为键。然后使用这个密钥。由于您有 ElementRef 的两个定义,因此角度无法解决提供者。 take.ms/Vq5F0 -
Systemjs 将
core.umd.js加载为file:///... -
我已成功使用
window共享@angular/* 模块以在全球范围内存储模块。它并不优雅,但它有工作的优点......在我的插件中导入角度核心我使用const NgModule = window.angular.core.NgModule而不是传统的import {NgModule} from "@angular/core",在我的index.html中,我在窗口中导入所有需要共享的模块(@angular/core、@angular/common等..)。我还阅读/观看了 Angular Elements,这似乎非常适合这个用例:youtu.be/ljsOPm4MMEo?t=13m20s.