Angular 2.1.0dynamic创build子组件

我正在试图做的angular 2.1.0正在创build应该注入到父组件的飞行中的子组件。 例如,父组件是lessonDetails ,它包含所有课程的共享内容,例如button,如Go to previous lessonGo to next lesson以及其他内容。 基于路由参数,应该是子组件的课程内容需要dynamic注入父组件 。 子组件(课程内容)的HTML被定义为外部的纯string,它可以是如下的对象:

 export const LESSONS = { "lesson-1": `<p> lesson 1 </p>`, "lesson-2": `<p> lesson 2 </p>` } 

通过innerHtml父组件模板中可以很容易地解决问题。

 <div [innerHTML]="lessonContent"></div> 

如果每次路由参数变化,父组件的属性lessonContent将改变(内容(新模板)将从LESSON对象中取得),导致父组件模板被更新。 这个工程,但angular将不处理通过innerHtml注入的内容,所以不可能使用routerLink和其他的东西。

在新的angular度释放之前,我使用来自http://blog.lacolaco.net/post/dynamic-component-creation-in-angular-2/的解决scheme解决了这个问题,其中我一直使用ComponentMetadataComponentResolver一起创build子组件苍蝇,就像:

 const metadata = new ComponentMetadata({ template: this.templateString, }); 

其中templateString作为子组件的Input属性传递给子组件。 MetaDataComponentResolver都在angular 2.1.0被弃用/删除。

所以问题不仅在于dynamic组件的创build,就像在几个相关的SO问题中所描述的一样,如果我为每个课程内容定义了组件,问题将会更容易解决。 这意味着我需要为100个不同的课程预先声明100个不同的组件。 弃用的元数据提供的行为就像在单个组件的运行时更新模板(创build和销毁路由参数更改中的单个组件)。

更新1:在最近的angular度版本中,似乎需要dynamic创build/注入的所有组件都需要在entryComponents中的@NgModule预定义。 所以在我看来,与上面的问题相关,如果我需要有100课(需要dynamic地创build组件),这意味着我需要预先定义100个组件

更新2:基于更新1,可通过以下方式通过ViewContainerRef.createComponent()完成:

 // lessons.ts @Component({ template: html string loaded from somewhere }) class LESSON_1 {} @Component({ template: html string loaded from somewhere }) class LESSON_2 {} // exported value to be used in entryComponents in @NgModule export const LESSON_CONTENT_COMPONENTS = [ LESSON_1, LESSON_2 ] 

现在在路由参数的父组件改变

 const key = // determine lesson name from route params /** * class is just buzzword for function * find Component by name (LESSON_1 for example) * here name is property of function (class) */ const dynamicComponent = _.find(LESSON_CONTENT_COMPONENTS, { name: key }); const lessonContentFactory = this.resolver.resolveComponentFactory(dynamicComponent); this.componentRef = this.lessonContent.createComponent(lessonContentFactory); 

父模板如下所示:

 <div *ngIf="something" #lessonContentContainer></div> 

其中lessonContentContainer装饰在@ViewChildren属性和lessonContent装饰为@ViewChild和它在ngAfterViewInit ()初始化为:

 ngAfterViewInit () { this.lessonContentContainer.changes.subscribe((items) => { this.lessonContent = items.first; this.subscription = this.activatedRoute.params.subscribe((params) => { // logic that needs to show lessons }) }) } 

解决scheme有一个缺点 ,那就是所有组件(LESSON_CONTENT_COMPONENTS)都需要预定义。
有没有办法使用一个单一的组件,并在运行时更改该组件的模板(路线参数更改)?

你可以使用下面的HtmlOutlet指令:

 import { Component, Directive, NgModule, Input, ViewContainerRef, Compiler, ComponentFactory, ModuleWithComponentFactories, ComponentRef, ReflectiveInjector } from '@angular/core'; import { RouterModule } from '@angular/router'; import { CommonModule } from '@angular/common'; export function createComponentFactory(compiler: Compiler, metadata: Component): Promise<ComponentFactory<any>> { const cmpClass = class DynamicComponent {}; const decoratedCmp = Component(metadata)(cmpClass); @NgModule({ imports: [CommonModule, RouterModule], declarations: [decoratedCmp] }) class DynamicHtmlModule { } return compiler.compileModuleAndAllComponentsAsync(DynamicHtmlModule) .then((moduleWithComponentFactory: ModuleWithComponentFactories<any>) => { return moduleWithComponentFactory.componentFactories.find(x => x.componentType === decoratedCmp); }); } @Directive({ selector: 'html-outlet' }) export class HtmlOutlet { @Input() html: string; cmpRef: ComponentRef<any>; constructor(private vcRef: ViewContainerRef, private compiler: Compiler) { } ngOnChanges() { const html = this.html; if (!html) return; if(this.cmpRef) { this.cmpRef.destroy(); } const compMetadata = new Component({ selector: 'dynamic-html', template: this.html, }); createComponentFactory(this.compiler, compMetadata) .then(factory => { const injector = ReflectiveInjector.fromResolvedProviders([], this.vcRef.parentInjector); this.cmpRef = this.vcRef.createComponent(factory, 0, injector, []); }); } ngOnDestroy() { if(this.cmpRef) { this.cmpRef.destroy(); } } } 

另请参阅Plunker示例

自定义组件的例子

对于AOT编译,请参阅这些线程

另请参阅github Webpack AOT示例 https://github.com/alexzuza/angular2-build-examples/tree/master/ngc-webpack