我想动态创建一个模板。这应该用于在运行时构建ComponentType,并将其放置(甚至替换)到宿主组件内部的某个位置。

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

ComponentResolver is deprecated for dynamic compilation.
Use ComponentFactoryResolver together with @NgModule/@Component.entryComponents or ANALYZE_FOR_ENTRY_COMPONENTS provider instead.
For runtime compile only, you can also use Compiler.compileComponentSync/Async.

我找到了这个文档(Angular 2同步动态组件创建)

你要明白我可以用任何一种

一种带有ComponentFactoryResolver的动态ngIf。如果我在@Component({entryComponents: [comp1, comp2],…})内部传递已知的组件-我可以使用.resolveComponentFactory(componentToRender); 真正的运行时编译,使用编译器…

但问题是如何使用编译器?上面的说明说,我应该调用:Compiler.compileComponentSync/Async -那么如何?

为例。我想为一种设置创建(基于一些配置条件)这种模板

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

在另一种情况下,这个(字符串编辑器被文本编辑器取代)

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

等等(根据属性类型设置不同的数字/日期/引用编辑器,为某些用户跳过一些属性……)例如,这是一个例子,实际的配置可以生成更多不同和复杂的模板。

模板正在改变,所以我不能使用ComponentFactoryResolver和传递现有的…我需要一个解决方案与编译器。


当前回答

在Radmin的精彩回答之后,每个使用angular-cli 1.0.0-beta版本的人都需要做一个小小的调整。22岁及以上。

COMPILER_PROVIDERScan不再被导入(详见angular-cli GitHub)。

因此,这里的解决方法是在providers部分完全不使用COMPILER_PROVIDERS和JitCompiler,而是在类型构建器类中使用'@angular/compiler'中的JitCompilerFactory,就像这样:

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

正如您所看到的,它是不可注入的,因此与DI没有依赖关系。这个解决方案也适用于不使用angular-cli的项目。

其他回答

我一定是迟到了,这里没有一个解决方案对我有帮助——太乱了,感觉像是一个太多的变通办法。

我最终使用了Angular 4.0.0-beta。6 ngComponentOutlet。

这给了我最短、最简单的解决方案,所有这些都写在动态组件的文件中。

下面是一个简单的例子,它只是接收文本并将其放在模板中,但显然你可以根据自己的需要进行更改:

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;
  }
}

简短说明: My-component—动态组件在其中呈现的组件 DynamicComponent -要动态构建的组件,它在my-component内部呈现

别忘了把所有的angular库升级到^ angular 4.0.0

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

更新

同样适用于angular 5。

如果你只需要一种解析动态字符串和通过选择器加载组件的方法,你可能还会发现ngx-dynamic-hooks库很有用。我最初创建这个是作为个人项目的一部分,但在周围没有看到类似的东西,所以我对它进行了一些优化并将其公之于众。

一些tidbids:

You can load any components into a dynamic string by their selector (or any other pattern of your choice!) Inputs and outputs can be se just like in a normal template Components can be nested without restrictions You can pass live data from the parent component into the dynamically loaded components (and even use it to bind inputs/outputs) You can control which components can load in each outlet and even which inputs/outputs you can give them The library uses Angular's built-in DOMSanitizer to be safe to use even with potentially unsafe input.

值得注意的是,它不像这里的其他响应那样依赖于运行时编译器。因此,您不能使用模板语法。另一方面,这意味着它既可以在JiT和aot模式下工作,也可以在Ivy和旧的模板引擎下工作,而且在一般情况下使用起来更加安全。

在这部《斯塔克布利茨》中可以看到它的作用。

我有一个简单的例子来展示如何做angular 2 rc6动态组件。

比方说,你有一个动态html template = template1,想要动态加载,首先包装成组件

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

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

在rc6中,必须使用@NgModule来包装这个组件。@NgModule,就像anglarJS 1中的module一样,它解耦了ng2应用程序的不同部分,因此:

@Component({
  template: template1,

})
class DynamicComponent {

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

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

现在你可以这样编译DynamicModule: this.compiler.compileModuleAndAllComponentsAsync (DynamicModule) ( factory => factory. componentfactories .find(x => x.p omenttype === DynamicComponent)

我们需要把上面的内容放到app. module .ts中来加载,请查看我的app.moudle.ts。 更多详细信息请查看: https://github.com/Longfld/DynamicalRouter/blob/master/app/MyRouterLink.ts和app.moudle.ts

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

在Ophir Stern的答案基础上,这里有一个与Angular 4中的AoT一起工作的变体。唯一的问题是我不能向DynamicComponent注入任何服务,但我可以接受。

注意:我还没有测试Angular 5。

import { Component, OnInit, Input, NgModule, NgModuleFactory, Compiler, EventEmitter, Output } from '@angular/core';
import { JitCompilerFactory } from '@angular/compiler';

export function createJitCompiler() {
  return new JitCompilerFactory([{
    useDebug: false,
    useJit: true
  }]).createCompiler();
}

type Bindings = {
  [key: string]: any;
};

@Component({
  selector: 'app-compile',
  template: `
    <div *ngIf="dynamicComponent && dynamicModule">
      <ng-container *ngComponentOutlet="dynamicComponent; ngModuleFactory: dynamicModule;">
      </ng-container>
    </div>
  `,
  styleUrls: ['./compile.component.scss'],
  providers: [{provide: Compiler, useFactory: createJitCompiler}]
})
export class CompileComponent implements OnInit {

  public dynamicComponent: any;
  public dynamicModule: NgModuleFactory<any>;

  @Input()
  public bindings: Bindings = {};
  @Input()
  public template: string = '';

  constructor(private compiler: Compiler) { }

  public ngOnInit() {

    try {
      this.loadDynamicContent();
    } catch (err) {
      console.log('Error during template parsing: ', err);
    }

  }

  private loadDynamicContent(): void {

    this.dynamicComponent = this.createNewComponent(this.template, this.bindings);
    this.dynamicModule = this.compiler.compileModuleSync(this.createComponentModule(this.dynamicComponent));

  }

  private createComponentModule(componentType: any): any {

    const runtimeComponentModule = NgModule({
      imports: [],
      declarations: [
        componentType
      ],
      entryComponents: [componentType]
    })(class RuntimeComponentModule { });

    return runtimeComponentModule;

  }

  private createNewComponent(template: string, bindings: Bindings): any {

    const dynamicComponent = Component({
      selector: 'app-dynamic-component',
      template: template
    })(class DynamicComponent implements OnInit {

      public bindings: Bindings;

      constructor() { }

      public ngOnInit() {
        this.bindings = bindings;
      }

    });

    return dynamicComponent;

  }

}

希望这能有所帮助。

干杯!

在Radmin的精彩回答之后,每个使用angular-cli 1.0.0-beta版本的人都需要做一个小小的调整。22岁及以上。

COMPILER_PROVIDERScan不再被导入(详见angular-cli GitHub)。

因此,这里的解决方法是在providers部分完全不使用COMPILER_PROVIDERS和JitCompiler,而是在类型构建器类中使用'@angular/compiler'中的JitCompilerFactory,就像这样:

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

正如您所看到的,它是不可注入的,因此与DI没有依赖关系。这个解决方案也适用于不使用angular-cli的项目。