Angular 4 加载动态组件时出现 AOT 编译错误:未加载运行时编译器
Angular 4 AOT Compilation Error while loading a Dynamic Component: Runtime compiler is not loaded
我的 Angular 应用程序必须处理加载动态组件。使用 JIT ng serve or, ng build
编译,一切正常。即使使用 AOT ng serve --prod or, ng build --prod
,我仍然可以成功构建。此外,应用程序中的所有延迟加载模块都按预期工作。但是一旦我从登录页面 initiate an event to load a dynamic component
,我就会收到以下错误:
vendor.fbd3ddffb0a9e35bbf55.bundle.js:1 ERROR Error: Uncaught (in promise):
Error: Runtime compiler is not loaded
Error: Runtime compiler is not loaded
at Z (vendor.fbd3ddffb0a9e35bbf55.bundle.js:1)
at t.compileModuleAndAllComponentsAsync
(vendor.fbd3ddffb0a9e35bbf55.bundle.js:1)
at dynamic.module.3b05550d9afcedd58855.chunk.js:1
at t.invoke (polyfills.a58272fc2ef255219061.bundle.js:1)
at Object.onInvoke (vendor.fbd3ddffb0a9e35bbf55.bundle.js:1)
at t.invoke (polyfills.a58272fc2ef255219061.bundle.js:1)
at r.run (polyfills.a58272fc2ef255219061.bundle.js:1)
at polyfills.a58272fc2ef255219061.bundle.js:1
at t.invokeTask (polyfills.a58272fc2ef255219061.bundle.js:1)
at Object.onInvokeTask (vendor.fbd3ddffb0a9e35bbf55.bundle.js:1)
at Z (vendor.fbd3ddffb0a9e35bbf55.bundle.js:1)
at t.compileModuleAndAllComponentsAsync
(vendor.fbd3ddffb0a9e35bbf55.bundle.js:1)
at dynamic.module.3b05550d9afcedd58855.chunk.js:1
at t.invoke (polyfills.a58272fc2ef255219061.bundle.js:1)
at Object.onInvoke (vendor.fbd3ddffb0a9e35bbf55.bundle.js:1)
at t.invoke (polyfills.a58272fc2ef255219061.bundle.js:1)
at r.run (polyfills.a58272fc2ef255219061.bundle.js:1)
at polyfills.a58272fc2ef255219061.bundle.js:1
at t.invokeTask (polyfills.a58272fc2ef255219061.bundle.js:1)
at Object.onInvokeTask (vendor.fbd3ddffb0a9e35bbf55.bundle.js:1)
at c (polyfills.a58272fc2ef255219061.bundle.js:1)
at polyfills.a58272fc2ef255219061.bundle.js:1
at t.invokeTask (polyfills.a58272fc2ef255219061.bundle.js:1)
at Object.onInvokeTask (vendor.fbd3ddffb0a9e35bbf55.bundle.js:1)
at t.invokeTask (polyfills.a58272fc2ef255219061.bundle.js:1)
at r.runTask (polyfills.a58272fc2ef255219061.bundle.js:1)
at o (polyfills.a58272fc2ef255219061.bundle.js:1)
at <anonymous>`
我通过在动态组件中应用注入器来消除上述错误:
export class DynamicComponent {
private injector: Injector;
private compiler: Compiler;
constructor(injector: Injector) {
this.injector = ReflectiveInjector.resolveAndCreate(COMPILER_PROVIDERS,
injector);
this.compiler = this.injector.get(Compiler);
}
}
上述错误消失后,我现在收到以下错误:
vendor.fbd3ddffb0a9e35bbf55.bundle.js:1 ERROR Error: Uncaught (in promise):
Error: No NgModule metadata found for 'l'.
Error: No NgModule metadata found for 'l'.
at t.FDXN.t.resolve (dynamic.module.c493eec4648091b2c9b3.chunk.js:1)
at t.FDXN.t.getNgModuleMetadata (dynamic.module.c493eec4648091b2c9b3.chunk.js:1)
at t.FDXN.t._loadModules (dynamic.module.c493eec4648091b2c9b3.chunk.js:1)
at t.FDXN.t._compileModuleAndAllComponents (dynamic.module.c493eec4648091b2c9b3.chunk.js:1)
at t.FDXN.t.compileModuleAndAllComponentsAsync (dynamic.module.c493eec4648091b2c9b3.chunk.js:1)
at dynamic.module.c493eec4648091b2c9b3.chunk.js:1
at t.invoke (polyfills.a58272fc2ef255219061.bundle.js:1)
at Object.onInvoke (vendor.fbd3ddffb0a9e35bbf55.bundle.js:1)
at t.invoke (polyfills.a58272fc2ef255219061.bundle.js:1)
at r.run (polyfills.a58272fc2ef255219061.bundle.js:1)
at t.FDXN.t.resolve (dynamic.module.c493eec4648091b2c9b3.chunk.js:1)
at t.FDXN.t.getNgModuleMetadata (dynamic.module.c493eec4648091b2c9b3.chunk.js:1)
at t.FDXN.t._loadModules (dynamic.module.c493eec4648091b2c9b3.chunk.js:1)
at t.FDXN.t._compileModuleAndAllComponents (dynamic.module.c493eec4648091b2c9b3.chunk.js:1)
at t.FDXN.t.compileModuleAndAllComponentsAsync (dynamic.module.c493eec4648091b2c9b3.chunk.js:1)
at dynamic.module.c493eec4648091b2c9b3.chunk.js:1
at t.invoke (polyfills.a58272fc2ef255219061.bundle.js:1)
at Object.onInvoke (vendor.fbd3ddffb0a9e35bbf55.bundle.js:1)
at t.invoke (polyfills.a58272fc2ef255219061.bundle.js:1)
at r.run (polyfills.a58272fc2ef255219061.bundle.js:1)
at c (polyfills.a58272fc2ef255219061.bundle.js:1)
at polyfills.a58272fc2ef255219061.bundle.js:1
at t.invokeTask (polyfills.a58272fc2ef255219061.bundle.js:1)
at Object.onInvokeTask (vendor.fbd3ddffb0a9e35bbf55.bundle.js:1)
at t.invokeTask (polyfills.a58272fc2ef255219061.bundle.js:1)
at r.runTask (polyfills.a58272fc2ef255219061.bundle.js:1)
at o (polyfills.a58272fc2ef255219061.bundle.js:1)
at <anonymous>
我在互联网上发现了很多与此问题相关的帖子,包括堆栈溢出,但 none 其中恰好适合我。
我的动态组件是这样的:
import { Component, Input, Output, ViewContainerRef, Compiler, ComponentFactory, ComponentFactoryResolver, ModuleWithComponentFactories, ComponentRef, ReflectiveInjector, SystemJsNgModuleLoader, OnInit, OnDestroy, ViewChild, Injector } from '@angular/core';
import { Http } from '@angular/http';
import { Observable, Subscription } from 'rxjs/Rx';
import { JitCompiler } from '@angular/compiler';
import { COMPILER_PROVIDERS } from '@angular/compiler';
import * as _ from 'lodash';
import { Page } from './interfaces/page';
import { PageService } from './services/page.service';
import { ActivePageService } from './services/active-page.service';
export class ModuleNode { modulePath: string; componentName: string; }
@Component({
selector: 'app-dynamic-viewer',
host: { 'class': 'template-wrapper dynamicviewer' },
templateUrl: './dynamic.component.html',
styleUrls: ['./dynamic.component.less'],
providers: [PageService, ActivePageService]
})
export class DynamicComponent implements OnInit, OnDestroy {
module: ModuleNode;
componentRef: ComponentRef<any>;
@ViewChild('pageContainer', { read: ViewContainerRef }) public pageHost;
public activePagesData: string[];
public pageData: Page[];
public currentPage: Page;
private injector: Injector;
private compiler: Compiler;
constructor(
injector: Injector,
private activePageService: activePageService,
private pageService: pageService,
private viewContainerRef: ViewContainerRef,
private componentFactoryResolver: ComponentFactoryResolver,
private systemJsNgModuleLoader: SystemJsNgModuleLoader
) {
this.injector = ReflectiveInjector.resolveAndCreate(COMPILER_PROVIDERS,
injector);
this.compiler = this.injector.get(Compiler);
}
ngOnInit() {
this.getActivePageData();
}
openWebApp(currentModule: any) {
this.destoryComponent();
this.systemJsNgModuleLoader.load(currentModule.modulePath)
.then((moduleFactory) => {
this.compiler.compileModuleAndAllComponentsAsync<any>(moduleFactory.moduleType)
.then((factory: ModuleWithComponentFactories<any>) => {
return factory.componentFactories.find(x => x.componentType.name === currentModule.componentName);
})
.then(componentFactory => {
const moduleRef = moduleFactory.create(this.pageHost.parentInjector);
this.componentRef = this.pageHost.createComponent(componentFactory, 0, moduleRef.injector);
});
});
}
destoryComponent() {
if (this.componentRef) {
this.componentRef.destroy();
}
}
ngOnDestroy() {
this.destoryComponent();
}
getPageData() {
this.pageService.getPageData().subscribe(res => {
for (const page of res) {
page.active = (this.activePagesData.indexOf(page.name) !== -1)
}
this.pageData = res;
});
}
getActivePageData() {
this.activePageService.getActivePageData().subscribe(res => {
this.activePagesData = res;
this.getPageData();
});
}
selectPage(page: Page) {
if (page.active) {
this.currentPage = page;
if (this.componentRef) {
this.componentRef.destroy();
}
this.module = new ModuleNode();
this.module.modulePath = this.currentPage.modulePath;
this.module.componentName = this.currentPage.componentName;
this.openWebApp(this.module);
}
}
}
应用环境:
@angular/cli: 1.3.0-beta.1
node: 6.9.4
os: win32 x64
@angular version: 4.3.6
有什么解决办法吗?任何输入将不胜感激。
我也遇到了同样的问题。我就是这样做的。比方说,UserComponent needs to be loaded dynamically
从您的着陆页进行 AOT 编译。
user.module.ts
@NgModule({
...
entryComponents: [UserComponent]
})
export class UserModule {
static entry = UserComponent
}
您的基本着陆页可以是这样的:
dynamic.component.htlm
<div>
<ng-template #pageContainer></ng-template>
</div>
<div *ngFor="let page of pageData">
<div (click)="selectPage(page)">
<div>{{page.title}}</div>
</div>
</div>
当您 select 从您的着陆页访问页面(即尝试动态加载组件)时,请提供相应模块的绝对路径。因此,用户页面的 currentPage.modulePath
的值可能类似于 app/modules/pages/user/user.module#UserModule
。最后,您可以像这样加载入口组件:
openWebApp(path: string) {
this.systemJsNgModuleLoader.load(path)
.then((moduleFactory: NgModuleFactory<any>) => {
const entryComponent = (<any>moduleFactory.moduleType).entry;
const moduleRef = moduleFactory.create(this.injector);
const compFactory = moduleRef.componentFactoryResolver.resolveComponentFactory(entryComponent);
this.componentRef = this.pageHost.createComponent(compFactory);
});
}
因此,您的动态组件如下所示:
dynamic.component.ts
import { Component, Input, Output, NgModuleFactory, ViewContainerRef, Compiler, ComponentFactory, ComponentFactoryResolver, ModuleWithComponentFactories, ComponentRef, ReflectiveInjector, SystemJsNgModuleLoader, OnInit, OnDestroy, ViewChild, Injector } from '@angular/core';
import { Http } from '@angular/http';
import { Observable, Subscription } from 'rxjs/Rx';
import { COMPILER_PROVIDERS } from '@angular/compiler';
import * as _ from 'lodash';
import { Page } from './interfaces/page';
import { PageService } from './services/page.service';
import { ActivePageService } from './services/active-page.service';
@Component({
selector: 'app-dynamic-viewer',
host: { 'class': 'template-wrapper dynamicviewer' },
templateUrl: './dynamic.component.html',
styleUrls: ['./dynamic.component.less'],
providers: [PageService, ActivePageService]
})
export class DynamicComponent implements OnInit, OnDestroy {
componentRef: ComponentRef<any>;
@ViewChild('pageContainer', { read: ViewContainerRef }) public pageHost;
public activePagesData: string[];
public pageData: Page[];
public currentPage: Page;
private injector: Injector;
private compiler: Compiler;
constructor(
injector: Injector,
private activePageService: ActivePageService,
private pageService: PageService,
private viewContainerRef: ViewContainerRef,
private componentFactoryResolver: ComponentFactoryResolver,
private systemJsNgModuleLoader: SystemJsNgModuleLoader
) {
this.injector = ReflectiveInjector.resolveAndCreate(COMPILER_PROVIDERS, injector);
this.compiler = this.injector.get(Compiler);
}
ngOnInit() {
this.getActivePageData();
}
selectPage(page: Page) {
if (page.active) {
this.currentPage = page;
if (this.componentRef) {
this.componentRef.destroy();
}
this.openWebApp(this.currentPage.modulePath);
}
}
openWebApp(path: string) {
this.destoryComponent();
this.systemJsNgModuleLoader.load(path)
.then((moduleFactory: NgModuleFactory<any>) => {
const entryComponent = (<any>moduleFactory.moduleType).entry;
const moduleRef = moduleFactory.create(this.injector);
const compFactory = moduleRef.componentFactoryResolver.resolveComponentFactory(entryComponent);
this.componentRef = this.pageHost.createComponent(compFactory);
});
}
destoryComponent() {
if (this.componentRef) {
this.componentRef.destroy();
}
}
ngOnDestroy() {
this.destoryComponent();
}
getPageData() {
this.pageService.getPageData().subscribe(res => {
for (const page of res) {
page.active = (this.activePagesData.indexOf(page.name) !== -1)
}
this.pageData = res;
});
}
getActivePageData() {
this.activePageService.getActivePageData().subscribe(res => {
this.activePagesData = res;
this.getPageData();
});
}
}
我的 Angular 应用程序必须处理加载动态组件。使用 JIT ng serve or, ng build
编译,一切正常。即使使用 AOT ng serve --prod or, ng build --prod
,我仍然可以成功构建。此外,应用程序中的所有延迟加载模块都按预期工作。但是一旦我从登录页面 initiate an event to load a dynamic component
,我就会收到以下错误:
vendor.fbd3ddffb0a9e35bbf55.bundle.js:1 ERROR Error: Uncaught (in promise):
Error: Runtime compiler is not loaded
Error: Runtime compiler is not loaded
at Z (vendor.fbd3ddffb0a9e35bbf55.bundle.js:1)
at t.compileModuleAndAllComponentsAsync
(vendor.fbd3ddffb0a9e35bbf55.bundle.js:1)
at dynamic.module.3b05550d9afcedd58855.chunk.js:1
at t.invoke (polyfills.a58272fc2ef255219061.bundle.js:1)
at Object.onInvoke (vendor.fbd3ddffb0a9e35bbf55.bundle.js:1)
at t.invoke (polyfills.a58272fc2ef255219061.bundle.js:1)
at r.run (polyfills.a58272fc2ef255219061.bundle.js:1)
at polyfills.a58272fc2ef255219061.bundle.js:1
at t.invokeTask (polyfills.a58272fc2ef255219061.bundle.js:1)
at Object.onInvokeTask (vendor.fbd3ddffb0a9e35bbf55.bundle.js:1)
at Z (vendor.fbd3ddffb0a9e35bbf55.bundle.js:1)
at t.compileModuleAndAllComponentsAsync
(vendor.fbd3ddffb0a9e35bbf55.bundle.js:1)
at dynamic.module.3b05550d9afcedd58855.chunk.js:1
at t.invoke (polyfills.a58272fc2ef255219061.bundle.js:1)
at Object.onInvoke (vendor.fbd3ddffb0a9e35bbf55.bundle.js:1)
at t.invoke (polyfills.a58272fc2ef255219061.bundle.js:1)
at r.run (polyfills.a58272fc2ef255219061.bundle.js:1)
at polyfills.a58272fc2ef255219061.bundle.js:1
at t.invokeTask (polyfills.a58272fc2ef255219061.bundle.js:1)
at Object.onInvokeTask (vendor.fbd3ddffb0a9e35bbf55.bundle.js:1)
at c (polyfills.a58272fc2ef255219061.bundle.js:1)
at polyfills.a58272fc2ef255219061.bundle.js:1
at t.invokeTask (polyfills.a58272fc2ef255219061.bundle.js:1)
at Object.onInvokeTask (vendor.fbd3ddffb0a9e35bbf55.bundle.js:1)
at t.invokeTask (polyfills.a58272fc2ef255219061.bundle.js:1)
at r.runTask (polyfills.a58272fc2ef255219061.bundle.js:1)
at o (polyfills.a58272fc2ef255219061.bundle.js:1)
at <anonymous>`
我通过在动态组件中应用注入器来消除上述错误:
export class DynamicComponent {
private injector: Injector;
private compiler: Compiler;
constructor(injector: Injector) {
this.injector = ReflectiveInjector.resolveAndCreate(COMPILER_PROVIDERS,
injector);
this.compiler = this.injector.get(Compiler);
}
}
上述错误消失后,我现在收到以下错误:
vendor.fbd3ddffb0a9e35bbf55.bundle.js:1 ERROR Error: Uncaught (in promise):
Error: No NgModule metadata found for 'l'.
Error: No NgModule metadata found for 'l'.
at t.FDXN.t.resolve (dynamic.module.c493eec4648091b2c9b3.chunk.js:1)
at t.FDXN.t.getNgModuleMetadata (dynamic.module.c493eec4648091b2c9b3.chunk.js:1)
at t.FDXN.t._loadModules (dynamic.module.c493eec4648091b2c9b3.chunk.js:1)
at t.FDXN.t._compileModuleAndAllComponents (dynamic.module.c493eec4648091b2c9b3.chunk.js:1)
at t.FDXN.t.compileModuleAndAllComponentsAsync (dynamic.module.c493eec4648091b2c9b3.chunk.js:1)
at dynamic.module.c493eec4648091b2c9b3.chunk.js:1
at t.invoke (polyfills.a58272fc2ef255219061.bundle.js:1)
at Object.onInvoke (vendor.fbd3ddffb0a9e35bbf55.bundle.js:1)
at t.invoke (polyfills.a58272fc2ef255219061.bundle.js:1)
at r.run (polyfills.a58272fc2ef255219061.bundle.js:1)
at t.FDXN.t.resolve (dynamic.module.c493eec4648091b2c9b3.chunk.js:1)
at t.FDXN.t.getNgModuleMetadata (dynamic.module.c493eec4648091b2c9b3.chunk.js:1)
at t.FDXN.t._loadModules (dynamic.module.c493eec4648091b2c9b3.chunk.js:1)
at t.FDXN.t._compileModuleAndAllComponents (dynamic.module.c493eec4648091b2c9b3.chunk.js:1)
at t.FDXN.t.compileModuleAndAllComponentsAsync (dynamic.module.c493eec4648091b2c9b3.chunk.js:1)
at dynamic.module.c493eec4648091b2c9b3.chunk.js:1
at t.invoke (polyfills.a58272fc2ef255219061.bundle.js:1)
at Object.onInvoke (vendor.fbd3ddffb0a9e35bbf55.bundle.js:1)
at t.invoke (polyfills.a58272fc2ef255219061.bundle.js:1)
at r.run (polyfills.a58272fc2ef255219061.bundle.js:1)
at c (polyfills.a58272fc2ef255219061.bundle.js:1)
at polyfills.a58272fc2ef255219061.bundle.js:1
at t.invokeTask (polyfills.a58272fc2ef255219061.bundle.js:1)
at Object.onInvokeTask (vendor.fbd3ddffb0a9e35bbf55.bundle.js:1)
at t.invokeTask (polyfills.a58272fc2ef255219061.bundle.js:1)
at r.runTask (polyfills.a58272fc2ef255219061.bundle.js:1)
at o (polyfills.a58272fc2ef255219061.bundle.js:1)
at <anonymous>
我在互联网上发现了很多与此问题相关的帖子,包括堆栈溢出,但 none 其中恰好适合我。
我的动态组件是这样的:
import { Component, Input, Output, ViewContainerRef, Compiler, ComponentFactory, ComponentFactoryResolver, ModuleWithComponentFactories, ComponentRef, ReflectiveInjector, SystemJsNgModuleLoader, OnInit, OnDestroy, ViewChild, Injector } from '@angular/core';
import { Http } from '@angular/http';
import { Observable, Subscription } from 'rxjs/Rx';
import { JitCompiler } from '@angular/compiler';
import { COMPILER_PROVIDERS } from '@angular/compiler';
import * as _ from 'lodash';
import { Page } from './interfaces/page';
import { PageService } from './services/page.service';
import { ActivePageService } from './services/active-page.service';
export class ModuleNode { modulePath: string; componentName: string; }
@Component({
selector: 'app-dynamic-viewer',
host: { 'class': 'template-wrapper dynamicviewer' },
templateUrl: './dynamic.component.html',
styleUrls: ['./dynamic.component.less'],
providers: [PageService, ActivePageService]
})
export class DynamicComponent implements OnInit, OnDestroy {
module: ModuleNode;
componentRef: ComponentRef<any>;
@ViewChild('pageContainer', { read: ViewContainerRef }) public pageHost;
public activePagesData: string[];
public pageData: Page[];
public currentPage: Page;
private injector: Injector;
private compiler: Compiler;
constructor(
injector: Injector,
private activePageService: activePageService,
private pageService: pageService,
private viewContainerRef: ViewContainerRef,
private componentFactoryResolver: ComponentFactoryResolver,
private systemJsNgModuleLoader: SystemJsNgModuleLoader
) {
this.injector = ReflectiveInjector.resolveAndCreate(COMPILER_PROVIDERS,
injector);
this.compiler = this.injector.get(Compiler);
}
ngOnInit() {
this.getActivePageData();
}
openWebApp(currentModule: any) {
this.destoryComponent();
this.systemJsNgModuleLoader.load(currentModule.modulePath)
.then((moduleFactory) => {
this.compiler.compileModuleAndAllComponentsAsync<any>(moduleFactory.moduleType)
.then((factory: ModuleWithComponentFactories<any>) => {
return factory.componentFactories.find(x => x.componentType.name === currentModule.componentName);
})
.then(componentFactory => {
const moduleRef = moduleFactory.create(this.pageHost.parentInjector);
this.componentRef = this.pageHost.createComponent(componentFactory, 0, moduleRef.injector);
});
});
}
destoryComponent() {
if (this.componentRef) {
this.componentRef.destroy();
}
}
ngOnDestroy() {
this.destoryComponent();
}
getPageData() {
this.pageService.getPageData().subscribe(res => {
for (const page of res) {
page.active = (this.activePagesData.indexOf(page.name) !== -1)
}
this.pageData = res;
});
}
getActivePageData() {
this.activePageService.getActivePageData().subscribe(res => {
this.activePagesData = res;
this.getPageData();
});
}
selectPage(page: Page) {
if (page.active) {
this.currentPage = page;
if (this.componentRef) {
this.componentRef.destroy();
}
this.module = new ModuleNode();
this.module.modulePath = this.currentPage.modulePath;
this.module.componentName = this.currentPage.componentName;
this.openWebApp(this.module);
}
}
}
应用环境:
@angular/cli: 1.3.0-beta.1
node: 6.9.4
os: win32 x64
@angular version: 4.3.6
有什么解决办法吗?任何输入将不胜感激。
我也遇到了同样的问题。我就是这样做的。比方说,UserComponent needs to be loaded dynamically
从您的着陆页进行 AOT 编译。
user.module.ts
@NgModule({
...
entryComponents: [UserComponent]
})
export class UserModule {
static entry = UserComponent
}
您的基本着陆页可以是这样的:
dynamic.component.htlm
<div>
<ng-template #pageContainer></ng-template>
</div>
<div *ngFor="let page of pageData">
<div (click)="selectPage(page)">
<div>{{page.title}}</div>
</div>
</div>
当您 select 从您的着陆页访问页面(即尝试动态加载组件)时,请提供相应模块的绝对路径。因此,用户页面的 currentPage.modulePath
的值可能类似于 app/modules/pages/user/user.module#UserModule
。最后,您可以像这样加载入口组件:
openWebApp(path: string) {
this.systemJsNgModuleLoader.load(path)
.then((moduleFactory: NgModuleFactory<any>) => {
const entryComponent = (<any>moduleFactory.moduleType).entry;
const moduleRef = moduleFactory.create(this.injector);
const compFactory = moduleRef.componentFactoryResolver.resolveComponentFactory(entryComponent);
this.componentRef = this.pageHost.createComponent(compFactory);
});
}
因此,您的动态组件如下所示:
dynamic.component.ts
import { Component, Input, Output, NgModuleFactory, ViewContainerRef, Compiler, ComponentFactory, ComponentFactoryResolver, ModuleWithComponentFactories, ComponentRef, ReflectiveInjector, SystemJsNgModuleLoader, OnInit, OnDestroy, ViewChild, Injector } from '@angular/core';
import { Http } from '@angular/http';
import { Observable, Subscription } from 'rxjs/Rx';
import { COMPILER_PROVIDERS } from '@angular/compiler';
import * as _ from 'lodash';
import { Page } from './interfaces/page';
import { PageService } from './services/page.service';
import { ActivePageService } from './services/active-page.service';
@Component({
selector: 'app-dynamic-viewer',
host: { 'class': 'template-wrapper dynamicviewer' },
templateUrl: './dynamic.component.html',
styleUrls: ['./dynamic.component.less'],
providers: [PageService, ActivePageService]
})
export class DynamicComponent implements OnInit, OnDestroy {
componentRef: ComponentRef<any>;
@ViewChild('pageContainer', { read: ViewContainerRef }) public pageHost;
public activePagesData: string[];
public pageData: Page[];
public currentPage: Page;
private injector: Injector;
private compiler: Compiler;
constructor(
injector: Injector,
private activePageService: ActivePageService,
private pageService: PageService,
private viewContainerRef: ViewContainerRef,
private componentFactoryResolver: ComponentFactoryResolver,
private systemJsNgModuleLoader: SystemJsNgModuleLoader
) {
this.injector = ReflectiveInjector.resolveAndCreate(COMPILER_PROVIDERS, injector);
this.compiler = this.injector.get(Compiler);
}
ngOnInit() {
this.getActivePageData();
}
selectPage(page: Page) {
if (page.active) {
this.currentPage = page;
if (this.componentRef) {
this.componentRef.destroy();
}
this.openWebApp(this.currentPage.modulePath);
}
}
openWebApp(path: string) {
this.destoryComponent();
this.systemJsNgModuleLoader.load(path)
.then((moduleFactory: NgModuleFactory<any>) => {
const entryComponent = (<any>moduleFactory.moduleType).entry;
const moduleRef = moduleFactory.create(this.injector);
const compFactory = moduleRef.componentFactoryResolver.resolveComponentFactory(entryComponent);
this.componentRef = this.pageHost.createComponent(compFactory);
});
}
destoryComponent() {
if (this.componentRef) {
this.componentRef.destroy();
}
}
ngOnDestroy() {
this.destoryComponent();
}
getPageData() {
this.pageService.getPageData().subscribe(res => {
for (const page of res) {
page.active = (this.activePagesData.indexOf(page.name) !== -1)
}
this.pageData = res;
});
}
getActivePageData() {
this.activePageService.getActivePageData().subscribe(res => {
this.activePagesData = res;
this.getPageData();
});
}
}