我如何使用/创builddynamic模板来编译dynamic组件与Angular 2.0?

我想dynamic地创build模板 。 这应该用于在运行时构build一个ComponentType ,并将其放置(甚至replace)它在宿主组件内的某处。

直到RC4我使用ComponentResolver ,但与RC5我得到的消息:

不推荐使用ComponentResolver进行dynamic编译。 @NgModule/@Component.entryComponents使用ComponentFactoryResolver@NgModule/@Component.entryComponents或ANALYZE_FOR_ENTRY_COMPONENTS提供程序。 仅用于运行时编译 ,您也可以使用Compiler.compileComponentSync/Async

我发现这个(官方的angular2)文件

angular度2同步dynamic组件创build

并明白,我可以使用

  • 使用ComponentFactoryResolver的dynamicngIf 。 如果我将传递已知的组件到一个@Component({entryComponents: [comp1, comp2], ...}) – 我可以使用.resolveComponentFactory(componentToRender);
  • 真正的运行时编译, Compiler

但问题是如何使用该Compiler ? 上面的注释说我应该调用: Compiler.compileComponentSync/Async – 那么如何?

例如。 我想创build(基于一些configuration条件)这种模板的一种设置

 <form> <string-editor [propertyName]="'code'" [entity]="entity" ></string-editor> <string-editor [propertyName]="'description'" [entity]="entity" ></string-editor> ... 

而在另一种情况下,这个string-editor被replace为text-editor

 <form> <text-editor [propertyName]="'code'" [entity]="entity" ></text-editor> ... 

等等(不同的数量/date/参考editors按物业types,跳过一些用户的属性…) 。 即这是一个例子,真正的configuration可以产生更多不同和复杂的模板。

模板正在改变 ,所以我不能使用ComponentFactoryResolver并通过现有的…我需要Compiler解决scheme


AOT和JitCompiler (以前的RuntimeCompiler)

你想使用AOT的function(提前编译)? 你得到:

错误:遇到的错误静态parsing符号值。 函数调用不被支持。 考虑使用对导出函数的引用(原始.ts文件中的位置65:17)replace函数或lambda,在… / node_modules/@angular/compiler/src/compiler.d.ts中parsing符号COMPILER_PROVIDERS,

请留下您的评论,在这里投票:

AOT可以/将会使用COMPILER_PROVIDERS进行编码吗?

编辑 – 与2.3.0 (2016-12-07)

注意:为了得到以前版本的解决scheme,请检查这篇文章的历史

在这里讨论类似的话题Angular 2中的$ compile的等价物 。 我们需要使用JitCompilerNgModule 。 在这里阅读更多关于NgModule中的NgModule:

  • Angular 2 RC5 – NgModules,Lazy Loading和AoT编译

简而言之

一个工作plunker /示例 (dynamic模板,dynamic组件types,dynamic模块, JitCompiler ,…在行动)

主要是:
1)创build模板
2)在caching中findComponentFactory转到7)
3) – 创buildComponent
4) – 创buildModule
5) – 编译Module
6) – 返回(和caching供以后使用) ComponentFactory
7)使用TargetComponentFactory创build一个dynamicComponent的实例

这里是一个代码片段(更多这里 ) – 我们的自定义生成器正在返回只是构build/caching的ComponentFactory和视图的Target占位符消耗来创build一个DynamicComponent的实例

  // here we get a TEMPLATE with dynamic content === TODO var template = this.templateBuilder.prepareTemplate(this.entity, useTextarea); // here we get Factory (just compiled or from cache) this.typeBuilder .createComponentFactory(template) .then((factory: ComponentFactory<IHaveDynamicData>) => { // Target will instantiate and inject component (we'll keep reference to it) this.componentRef = this .dynamicComponentTarget .createComponent(factory); // let's inject @Inputs to component instance let component = this.componentRef.instance; component.entity = this.entity; //... }); 

这就是它 – 简而言之。 要获得更多的细节..阅读下面

TL&DR

观察一下运动员,并回来阅读细节,以防一些片段需要更多的解释

详细解释 – Angular2 RC6 ++和运行时组件

以下描述这个情景 ,我们会的

  1. 创build一个模块PartsModule:NgModule (小件的持有者)
  2. 创build另一个模块DynamicModule:NgModule ,它将包含我们的dynamic组件(以及dynamic引用PartsModule
  3. 创builddynamic模板(简单的方法)
  4. 创build新的Componenttypes(仅在模板已更改时)
  5. 创build新的RuntimeModule:NgModule 。 该模块将包含以前创build的Componenttypes
  6. 调用JitCompiler.compileModuleAndAllComponentsAsync(runtimeModule)来获取ComponentFactory
  7. 创build一个DynamicComponent的实例 – 查看目标占位符和ComponentFactory
  8. @Inputs分配给新实例 (从INPUT切换到TEXTAREA编辑) ,使用@Outputs

NgModule

我们需要一个NgModule

虽然我想展示一个非常简单的例子,在这种情况下,我需要三个模块(实际上是4个 – 但我不计数AppModule) 。 请采取这个, 而不是一个简单的片段作为一个真正坚实的dynamic组件生成器的基础。

所有小组件都会有一个模块,例如string-editortext-editor date-editornumber-editor …)

 @NgModule({ imports: [ CommonModule, FormsModule ], declarations: [ DYNAMIC_DIRECTIVES ], exports: [ DYNAMIC_DIRECTIVES, CommonModule, FormsModule ] }) export class PartsModule { } 

DYNAMIC_DIRECTIVES是可扩展的,用于保存用于dynamic组件模板/types的所有小部件。 检查应用程序/零件/ parts.module.ts

第二个将是我们的dynamic东西处理模块。 它将包含托pipe组件和一些提供商..这将是单身人士。 因此,我们将发布他们的标准方式 – forRoot()

 import { DynamicDetail } from './detail.view'; import { DynamicTypeBuilder } from './type.builder'; import { DynamicTemplateBuilder } from './template.builder'; @NgModule({ imports: [ PartsModule ], declarations: [ DynamicDetail ], exports: [ DynamicDetail], }) export class DynamicModule { static forRoot() { return { ngModule: DynamicModule, providers: [ // singletons accross the whole app DynamicTemplateBuilder, DynamicTypeBuilder ], }; } } 

检查forRoot()AppModule

最后,我们将需要一个adhoc运行时模块,但是稍后将作为DynamicTypeBuilder作业的一部分创build。

第四个模块,应用程序模块是保持声明编译器提供者的模块:

 ... import { COMPILER_PROVIDERS } from '@angular/compiler'; import { AppComponent } from './app.component'; import { DynamicModule } from './dynamic/dynamic.module'; @NgModule({ imports: [ BrowserModule, DynamicModule.forRoot() // singletons ], declarations: [ AppComponent], providers: [ COMPILER_PROVIDERS // this is an app singleton declaration ], 

阅读(读)更多关于NgModule那里:

  • Angular 2 RC5 – NgModules,Lazy Loading和AoT编译
  • Angular模块文档

模板生成

在我们的例子中,我们将处理这种实体的细节

 entity = { code: "ABC123", description: "A description of this Entity" }; 

要创build一个template ,我们使用这个简单/朴素的构build器。

真正的解决scheme,一个真正的模板生成器,是您的应用程序可以做很多事情的地方

 // plunker - app/dynamic/template.builder.ts import {Injectable} from "@angular/core"; @Injectable() export class DynamicTemplateBuilder { public prepareTemplate(entity: any, useTextarea: boolean){ let properties = Object.keys(entity); let template = "<form >"; let editorName = useTextarea ? "text-editor" : "string-editor"; properties.forEach((propertyName) =>{ template += ` <${editorName} [propertyName]="'${propertyName}'" [entity]="entity" ></${editorName}>`; }); return template + "</form>"; } } 

这里的一个技巧是 – 它build立一个模板,使用一些已知的属性,例如entity 。 这些属性(-ies)必须是dynamic组件的一部分,我们将在下一步创build。

为了使它更容易一些,我们可以使用一个接口来定义我们的模板构build器可以使用的属性。 这将通过我们的dynamic组件types来实现。

 export interface IHaveDynamicData { public entity: any; ... } 

一个ComponentFactory构build器

这里非常重要的是要记住:

我们的组件types,使用我们的DynamicTypeBuilder构build,可能会有所不同 – 但只能通过它的模板(上面创build) 。 组件的属性(input,输出或一些保护)仍然是相同的。 如果我们需要不同的属性,我们应该定义模板和types生成器的不同组合

所以,我们正在触摸我们解决scheme的核心。 Builder,将1)创buildComponentType 2)创build它的NgModule 3)编译ComponentFactory 4) caching它以备后用。

我们需要接受的依赖:

 // plunker - app/dynamic/type.builder.ts import { JitCompiler } from '@angular/compiler'; @Injectable() export class DynamicTypeBuilder { // wee need Dynamic component builder constructor( protected compiler: JitCompiler ) {} 

这里是一个片段如何获得一个ComponentFactory

 // plunker - app/dynamic/type.builder.ts // this object is singleton - so we can use this as a cache private _cacheOfFactories: {[templateKey: string]: ComponentFactory<IHaveDynamicData>} = {}; public createComponentFactory(template: string) : Promise<ComponentFactory<IHaveDynamicData>> { let factory = this._cacheOfFactories[template]; if (factory) { console.log("Module and Type are returned from cache") return new Promise((resolve) => { resolve(factory); }); } // unknown template ... let's create a Type for it let type = this.createNewComponent(template); let module = this.createComponentModule(type); return new Promise((resolve) => { this.compiler .compileModuleAndAllComponentsAsync(module) .then((moduleWithFactories) => { factory = _.find(moduleWithFactories.componentFactories , { componentType: type }); this._cacheOfFactories[template] = factory; resolve(factory); }); }); } 

上面我们创build并caching ComponentModule 。 因为如果模板(实际上是所有的真正的dynamic部分)是相同的..我们可以重用

这里有两个方法,它们代表了如何在运行时创build装饰类/types的非常酷的方法。 不仅@Component还有@NgModule

 protected createNewComponent (tmpl:string) { @Component({ selector: 'dynamic-component', template: tmpl, }) class CustomDynamicComponent implements IHaveDynamicData { @Input() public entity: any; }; // a component for this particular template return CustomDynamicComponent; } protected createComponentModule (componentType: any) { @NgModule({ imports: [ PartsModule, // there are 'text-editor', 'string-editor'... ], declarations: [ componentType ], }) class RuntimeComponentModule { } // a module for just this Type return RuntimeComponentModule; } 

重要:

我们的组件dynamictypes不同,但只是通过模板。 所以我们用这个事实caching它们。 这真的很重要。 Angular2也将caching这些types 。 如果我们将重新创build相同的模板string新types…我们将开始产生内存泄漏。

主机ComponentFactory使用的ComponentFactory

最后一部分是一个组件,托pipe我们dynamic组件的目标,例如<div #dynamicContentPlaceHolder></div> 。 我们得到一个引用,并使用ComponentFactory创build一个组件。 简而言之,这里是组件的所有部分(如果需要, 在这里打开plunker )

我们首先总结import报表:

 import {Component, ComponentRef,ViewChild,ViewContainerRef} from '@angular/core'; import {AfterViewInit,OnInit,OnDestroy,OnChanges,SimpleChange} from '@angular/core'; import { IHaveDynamicData, DynamicTypeBuilder } from './type.builder'; import { DynamicTemplateBuilder } from './template.builder'; @Component({ selector: 'dynamic-detail', template: ` <div> check/uncheck to use INPUT vs TEXTAREA: <input type="checkbox" #val (click)="refreshContent(val.checked)" /><hr /> <div #dynamicContentPlaceHolder></div> <hr /> entity: <pre>{{entity | json}}</pre> </div> `, }) export class DynamicDetail implements AfterViewInit, OnChanges, OnDestroy, OnInit { // wee need Dynamic component builder constructor( protected typeBuilder: DynamicTypeBuilder, protected templateBuilder: DynamicTemplateBuilder ) {} ... 

我们只收到模板和组件构build器。 接下来是我们的例子需要的属性(更多的评论)

 // reference for a <div> with #dynamicContentPlaceHolder @ViewChild('dynamicContentPlaceHolder', {read: ViewContainerRef}) protected dynamicComponentTarget: ViewContainerRef; // this will be reference to dynamic content - to be able to destroy it protected componentRef: ComponentRef<IHaveDynamicData>; // until ngAfterViewInit, we cannot start (firstly) to process dynamic stuff protected wasViewInitialized = false; // example entity ... to be recieved from other app parts // this is kind of candiate for @Input protected entity = { code: "ABC123", description: "A description of this Entity" }; 

在这种简单的情况下,我们的主机组件没有任何@Input 。 所以它不必对变化做出反应。 但是,尽pipe有这个事实(为即将到来的变化做好准备) ,如果组件已经(首先)启动,我们需要引入一些标志。 只有这样我们才能开始魔法。

最后,我们将使用我们的组件生成器及其刚刚编译/caching的 ComponentFacotry 。 我们的Target占位符将被要求用该工厂实例化Component

 protected refreshContent(useTextarea: boolean = false){ if (this.componentRef) { this.componentRef.destroy(); } // here we get a TEMPLATE with dynamic content === TODO var template = this.templateBuilder.prepareTemplate(this.entity, useTextarea); // here we get Factory (just compiled or from cache) this.typeBuilder .createComponentFactory(template) .then((factory: ComponentFactory<IHaveDynamicData>) => { // Target will instantiate and inject component (we'll keep reference to it) this.componentRef = this .dynamicComponentTarget .createComponent(factory); // let's inject @Inputs to component instance let component = this.componentRef.instance; component.entity = this.entity; //... }); } 

小的扩展

另外,我们需要保留对编译好的模板的引用。只要我们改变它,就可以正确地destroy()它。

 // this is the best moment where to start to process dynamic stuff public ngAfterViewInit(): void { this.wasViewInitialized = true; this.refreshContent(); } // wasViewInitialized is an IMPORTANT switch // when this component would have its own changing @Input() // - then we have to wait till view is intialized - first OnChange is too soon public ngOnChanges(changes: {[key: string]: SimpleChange}): void { if (this.wasViewInitialized) { return; } this.refreshContent(); } public ngOnDestroy(){ if (this.componentRef) { this.componentRef.destroy(); this.componentRef = null; } } 

DONE

这是非常多的。 不要忘记销毁dynamic构build的任何东西(ngOnDestroy) 。 另外,如果唯一的区别是他们的模板,一定要cachingdynamictypesmodules

在这里检查所有的行动

看到以前的版本(如RC5相关)这篇文章,检查历史

编辑(26/08/2017) :下面的解决scheme适用于Angular2和4.我已经更新它包含一个模板variables,并单击处理程序,并用Angular 4.3进行testing。
对于Angular4来说,在Ophir的回答中描述的ngComponentOutlet是一个更好的解决scheme。 但现在它不支持input和输出 。 如果接受[this PR]( https://github.com/angular/angular/pull/15362); ,则可以通过create事件返回的组件实例。
ng-dynamic-component可能是最好和最简单的解决scheme,但我还没有testing过。

@Long Field的答案是现货! 这是另一个(同步)的例子:

 import {Compiler, Component, NgModule, OnInit, ViewChild, ViewContainerRef} from '@angular/core' import {BrowserModule} from '@angular/platform-browser' @Component({ selector: 'my-app', template: `<h1>Dynamic template:</h1> <div #container></div>` }) export class App implements OnInit { @ViewChild('container', { read: ViewContainerRef }) container: ViewContainerRef; constructor(private compiler: Compiler) {} ngOnInit() { this.addComponent( `<h4 (click)="increaseCounter()"> Click to increase: {{counter}} `enter code here` </h4>`, { counter: 1, increaseCounter: function () { this.counter++; } } ); } private addComponent(template: string, properties?: any = {}) { @Component({template}) class TemplateComponent {} @NgModule({declarations: [TemplateComponent]}) class TemplateModule {} const mod = this.compiler.compileModuleAndAllComponentsSync(TemplateModule); const factory = mod.componentFactories.find((comp) => comp.componentType === TemplateComponent ); const component = this.container.createComponent(factory); Object.assign(component.instance, properties); // If properties are changed at a later stage, the change detection // may need to be triggered manually: // component.changeDetectorRef.detectChanges(); } } @NgModule({ imports: [ BrowserModule ], declarations: [ App ], bootstrap: [ App ] }) export class AppModule {} 

住在http://plnkr.co/edit/fdP9Oc

我一定是迟到了,这里的解决方法对我来说似乎是非常有帮助的 – 太杂乱了,感觉自己太过分了。

我最终做的是使用Angular 4.0.0-beta.6的ngComponentOutlet 。

这给了我所有写在dynamic组件文件中的最短,最简单的解决scheme。

  • 这是一个简单的例子,只是接收文本,并将其放在模板中,但显然你可以改变你所需要的:
 import { Component, OnInit, Input, NgModule, NgModuleFactory, Compiler } from '@angular/core'; @Component({ selector: 'my-component', template: `<ng-container *ngComponentOutlet="dynamicComponent; ngModuleFactory: dynamicModule;"></ng-container>`, styleUrls: ['my.component.css'] }) export class MyComponent implements OnInit { dynamicComponent; dynamicModule: NgModuleFactory<any>; @Input() text: string; constructor(private compiler: Compiler) { } ngOnInit() { this.dynamicComponent = this.createNewComponent(this.text); this.dynamicModule = this.compiler.compileModuleSync(this.createComponentModule(this.dynamicComponent)); } protected createComponentModule (componentType: any) { @NgModule({ imports: [], declarations: [ componentType ], entryComponents: [componentType] }) class RuntimeComponentModule { } // a module for just this Type return RuntimeComponentModule; } protected createNewComponent (text:string) { let template = `dynamically created template with text: ${text}`; @Component({ selector: 'dynamic-component', template: template }) class DynamicComponent implements OnInit{ text: any; } ngOnInit() { this.text = text; } return DynamicComponent; } } 
  • 简短的解释:
    1. my-component – 外部使用的注射组件
    2. DynamicComponent – 要dynamic构build的组件

不要忘了把所有的angular库升级到^ Angular 4.0.0

希望这会有所帮助,祝你好运!

Angular 2.0最终解决scheme

我决定把我学到的东西压缩成一个文件 。 与之前的RC5相比,这里特别值得一提。 请注意,此源文件包含AppModule和AppComponent。

 import { Component, Input, ReflectiveInjector, ViewContainerRef, Compiler, NgModule, ModuleWithComponentFactories, OnInit, ViewChild } from '@angular/core'; import {BrowserModule} from '@angular/platform-browser'; @Component({ selector: 'app-dynamic', template: '<h4>Dynamic Components</h4><br>' }) export class DynamicComponentRenderer implements OnInit { factory: ModuleWithComponentFactories<DynamicModule>; constructor(private vcRef: ViewContainerRef, private compiler: Compiler) { } ngOnInit() { if (!this.factory) { const dynamicComponents = { sayName1: {comp: SayNameComponent, inputs: {name: 'Andrew Wiles'}}, sayAge1: {comp: SayAgeComponent, inputs: {age: 30}}, sayName2: {comp: SayNameComponent, inputs: {name: 'Richard Taylor'}}, sayAge2: {comp: SayAgeComponent, inputs: {age: 25}}}; this.compiler.compileModuleAndAllComponentsAsync(DynamicModule) .then((moduleWithComponentFactories: ModuleWithComponentFactories<DynamicModule>) => { this.factory = moduleWithComponentFactories; Object.keys(dynamicComponents).forEach(k => { this.add(dynamicComponents[k]); }) }); } } addNewName(value: string) { this.add({comp: SayNameComponent, inputs: {name: value}}) } addNewAge(value: number) { this.add({comp: SayAgeComponent, inputs: {age: value}}) } add(comp: any) { const compFactory = this.factory.componentFactories.find(x => x.componentType === comp.comp); // If we don't want to hold a reference to the component type, we can also say: const compFactory = this.factory.componentFactories.find(x => x.selector === 'my-component-selector'); const injector = ReflectiveInjector.fromResolvedProviders([], this.vcRef.parentInjector); const cmpRef = this.vcRef.createComponent(compFactory, this.vcRef.length, injector, []); Object.keys(comp.inputs).forEach(i => cmpRef.instance[i] = comp.inputs[i]); } } @Component({ selector: 'app-age', template: '<div>My age is {{age}}!</div>' }) class SayAgeComponent { @Input() public age: number; }; @Component({ selector: 'app-name', template: '<div>My name is {{name}}!</div>' }) class SayNameComponent { @Input() public name: string; }; @NgModule({ imports: [BrowserModule], declarations: [SayAgeComponent, SayNameComponent] }) class DynamicModule {} @Component({ selector: 'app-root', template: ` <h3>{{message}}</h3> <app-dynamic #ad></app-dynamic> <br> <input #name type="text" placeholder="name"> <button (click)="ad.addNewName(name.value)">Add Name</button> <br> <input #age type="number" placeholder="age"> <button (click)="ad.addNewAge(age.value)">Add Age</button> `, }) export class AppComponent { message = 'this is app component'; @ViewChild(DynamicComponentRenderer) dcr; } @NgModule({ imports: [BrowserModule], declarations: [AppComponent, DynamicComponentRenderer], bootstrap: [AppComponent] }) export class AppModule {}` 

我有一个简单的例子来展示如何做angular2 RC6dynamic组件。

比方说,你有一个dynamic的html模板= template1,想要dynamic加载,首先换成组件

 @Component({template: template1}) class DynamicComponent {} 

这里template1为html,可能包含ng2组件

从rc6开始,必须有@NgModule包装这个组件。 @NgModule,就像anglarJS 1中的模块一样,它解耦了ng2应用程序的不同部分,所以:

 @Component({ template: template1, }) class DynamicComponent { } @NgModule({ imports: [BrowserModule,RouterModule], declarations: [DynamicComponent] }) class DynamicModule { } 

(这里导入RouterModule就像在我的例子中,在我的html中有一些路由组件,你可以在后面看到)

现在,您可以将DynamicModule编译为: this.compiler.compileModuleAndAllComponentsAsync(DynamicModule).then( factory => factory.componentFactories.find(x => x.componentType === DynamicComponent))

我们需要在app.moudule.ts中加载它,请参阅我的app.moudle.ts。 有关更多详细信息,请查看: https : //github.com/Longfld/DynamicalRouter/blob/master/app/MyRouterLink.ts和app.moudle.ts

并查看演示: http : //plnkr.co/edit/1fdAYP5PAbiHdJfTKgWo?p=preview

我想在Radim这篇非常出色的文章的基础上增加一些细节。

我采取了这个解决scheme,并进行了一些工作,并迅速遇到了一些限制。 我只是概述这些,然后给出解决scheme。

  • 首先,我无法在dynamic细节内渲染dynamic细节(基本上嵌套dynamicUI)。
  • 接下来的问题是我想要在解决scheme中提供的其中一个部分中提供dynamic细节。 最初的解决scheme也是不可能的。
  • 最后,在string编辑器这样的dynamic部分上使用模板URL是不可能的。

我根据这篇文章提出了另外一个问题,关于如何实现这些限制,可以在这里find:

在angular2中recursiondynamic模板编译

如果您遇到与我相同的问题,我将只概述这些限制的答案,因为这样可以使解决scheme更加灵活。 如果最初的重新更新也是很棒的。

要相互嵌套dynamic细节,您需要在type.builder.ts的import语句中添加DynamicModule.forRoot()

 protected createComponentModule (componentType: any) { @NgModule({ imports: [ PartsModule, DynamicModule.forRoot() //this line here ], declarations: [ componentType ], }) class RuntimeComponentModule { } // a module for just this Type return RuntimeComponentModule; } 

除此之外,在string编辑器或文本编辑器的其中一个部分内不可能使用<dynamic-detail>

为了启用,你需要改变parts.module.tsparts.module.ts

parts.module.ts里面你需要在DYNAMIC_DIRECTIVES添加DynamicDetail

 export const DYNAMIC_DIRECTIVES = [ forwardRef(() => StringEditor), forwardRef(() => TextEditor), DynamicDetail ]; 

同样在dynamic.module.ts中,您必须删除dynamicDetail,因为它们现在是部件的一部分

 @NgModule({ imports: [ PartsModule ], exports: [ PartsModule], }) 

可以在这里find一个修改后的plunker: http ://plnkr.co/edit/UYnQHF?p=preview(我没有解决这个问题,我只是信使: – D)

最后,不可能在dynamic组件上创build的部分使用模板。 解决scheme(或解决方法,我不确定是否是angular度错误或框架的错误使用)是在构造函数中创build一个编译器,而不是注入它。

  private _compiler; constructor(protected compiler: RuntimeCompiler) { const compilerFactory : CompilerFactory = platformBrowserDynamic().injector.get(CompilerFactory); this._compiler = compilerFactory.createCompiler([]); } 

然后使用_compiler进行编译,然后启用templateUrls。

 return new Promise((resolve) => { this._compiler .compileModuleAndAllComponentsAsync(module) .then((moduleWithFactories) => { let _ = window["_"]; factory = _.find(moduleWithFactories.componentFactories, { componentType: type }); this._cacheOfFactories[template] = factory; resolve(factory); }); }); 

希望这可以帮助别人!

最好的问候莫滕

跟随Radmin的出色答案,对于使用angular-cli版本1.0.0-beta.22及以上版本的人来说,需要做一些小小的调整。

COMPILER_PROVIDERS 不能再被导入 (详情见angular-cli GitHub )。

So the workaround there is to not use COMPILER_PROVIDERS and JitCompiler in the providers section at all, but use JitCompilerFactory from '@angular/compiler' instead like this inside the type builder class:

 private compiler: Compiler = new JitCompilerFactory([{useDebug: false, useJit: true}]).createCompiler(); 

As you can see, it is not injectable and thus has no dependencies with the DI. This solution should also work for projects not using angular-cli.

I myself am trying to see how can I update RC4 to RC5 and thus I stumbled upon this entry and new approach to dynamic component creation still holds a bit of mystery to me, so I wont suggest anything on component factory resolver.

But, what I can suggest is a bit clearer approach to component creation on this scenario – just use switch in template that would create string editor or text editor according to some condition, like this:

 <form [ngSwitch]="useTextarea"> <string-editor *ngSwitchCase="false" propertyName="'code'" [entity]="entity"></string-editor> <text-editor *ngSwitchCase="true" propertyName="'code'" [entity]="entity"></text-editor> </form> 

And by the way, "[" in [prop] expression have a meaning, this indicates one way data binding, hence you can and even should omit those in case if you know that you do not need to bind property to variable.

Solved this in Angular 2 Final version simply by using the dynamicComponent directive from ng-dynamic .

用法:

 <div *dynamicComponent="template; context: {text: text};"></div> 

Where template is your dynamic template and context can be set to any dynamic datamodel that you want your template to bind to.