我正在将一个电子应用程序从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>
抛出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
Angular:5.0.2
角度材质:5.0.0-rc1
答案 0 :(得分:2)
正如@yurzui在评论中解释的那样,@ angular / *依赖关系被加载了两次。作为一种解决方法,我发现使其工作的唯一方法是使用window
在应用程序和插件之间共享@angular对象(@angular/core
,@angular/common
,{{1} })。
在我的应用程序index.html中:
@angular/material
在我的插件中:
window.angular = {
core: require("@angular/core"),
common: require("@angular/common"),
material: require("@angular/material"),
...
}
它不是很优雅(再见树摇晃)但至少它有效...如果有人有一个更简单的解决方案,我会接受它:)
我遇到了关于Gitter关于@angular/element的讨论,这似乎很有希望,因为它创建了独立/自包含的Web组件,可以动态注入而不会遇到我遇到的问题 - https://www.youtube.com/watch?v=ljsOPm4MMEo&feature=youtu.be&t=13m20s。这是一个实验室项目,因此在当前版本中不可用,但已经有一些工作:https://github.com/angular/angular/pull/19469