在Angular 2中等效$ compile

pix*_*its 127 version-compatibility typescript angular2-compiler angular

我想手动编译一些包含HTML的指令.$compileAngular 2中的等价物是什么?

例如,在Angular 1中,我可以动态编译HTML片段并将其附加到DOM:

var e = angular.element('<div directive></div>');
element.append(e);
$compile(e)($scope);
Run Code Online (Sandbox Code Playgroud)

Rad*_*ler 127

Angular 2.3.0(2016-12-07)

要获取所有详细信息,请检查:

要看到这一点:

校长:

1)创建模板
2)创建组件
3)创建模块
4)编译模块
5)创建(和缓存)ComponentFactory
6)使用Target创建它的实例

快速概述如何创建组件

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;
}
Run Code Online (Sandbox Code Playgroud)

一种如何将组件注入NgModule的方法

createComponentModule (componentType: any) {
  @NgModule({
    imports: [
      PartsModule, // there are 'text-editor', 'string-editor'...
    ],
    declarations: [
      componentType
    ],
  })
  class RuntimeComponentModule
  {
  }
  // a module for just this Type
  return RuntimeComponentModule;
}
Run Code Online (Sandbox Code Playgroud)

一个代码片段如何创建ComponentFactory (并缓存它)

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);
            });
    });
}
Run Code Online (Sandbox Code Playgroud)

一段代码片段如何使用上述结果

  // 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;
        //...
    });
Run Code Online (Sandbox Code Playgroud)

完整描述及所有细节在此处阅读,或观察工作示例

.

.

OBSOLETE - 与Angular 2.0 RC5相关(仅限RC5)

要查看之前RC版本的先前解决方案,请搜索此帖子的历史记录

  • 这真的很难吗?我曾经能够做这样的事情:`$ compile($ element.contents())($ scope.$ new());`现在它有数百行代码,完成了NgModule的创建......这种事情让我想要避开NG2并转向更好的事情. (55认同)
  • 非常感谢,我正在寻找一个"ComponentFactory"和`ViewContainerRef`的工作示例来替换现在已弃用的DynamicComponentLoader. (2认同)
  • 如果您的示例可以与`@ angular/core`中的`Compiler`一起使用,那么使用`JitCompiler`有什么好处?http://plnkr.co/edit/UxgkiT?p=preview (2认同)
  • 噢,天哪,我只应该编写几行代码就可以编译一个小元素。我不太了解 (2认同)

ale*_*ods 33

注意:正如@BennyBottema在评论中提到的那样,现在不推荐使用DynamicComponentLoader,因此这个答案也是如此.


Angular2没有任何 $ compile等价物.您可以使用DynamicComoponentLoader和破解ES6类来动态编译代码(请参阅此插件):

import {Component, DynamicComponentLoader, ElementRef, OnInit} from 'angular2/core'

function compileToComponent(template, directives) {
  @Component({ 
    selector: 'fake', 
    template , directives
  })
  class FakeComponent {};
  return FakeComponent;
}

@Component({
  selector: 'hello',
  template: '<h1>Hello, Angular!</h1>'
})
class Hello {}

@Component({
  selector: 'my-app',
  template: '<div #container></div>',
})
export class App implements OnInit {
  constructor(
    private loader: DynamicComponentLoader, 
    private elementRef: ElementRef,
  ) {}

  ngOnInit() {} {
    const someDynamicHtml = `<hello></hello><h2>${Date.now()}</h2>`;

    this.loader.loadIntoLocation(
      compileToComponent(someDynamicHtml, [Hello])
      this.elementRef,
      'container'
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

但只有在html解析器位于angular2核心内部之前它才会起作用.

  • 由于rc1 DynamicComponentLoader已被弃用 (13认同)
  • 回答我自己的问题:通过将数据传递给编译功能是可能的.这里的插件http://plnkr.co/edit/dK6l7jiWt535jOw1Htct?p=preview (2认同)

Cod*_*-EZ 15

我使用的Angular版本 - Angular 4.2.0

Angular 4提供了ComponentFactoryResolver来在运行时加载组件.这是Angular 1.0 中$ compile的一种相同实现, 可满足您的需求

在下面的示例中,我将ImageWidget 组件动态加载到DashboardTileComponent中

要加载组件,您需要一个可以应用于ng-template的指令, 这将有助于放置动态组件

WidgetHostDirective

 import { Directive, ViewContainerRef } from '@angular/core';

    @Directive({
      selector: '[widget-host]',
    })
    export class DashboardTileWidgetHostDirective {
      constructor(public viewContainerRef: ViewContainerRef) { 


      }
    }
Run Code Online (Sandbox Code Playgroud)

此指令注入ViewContainerRef以访问将托管动态添加组件的元素的视图容器.

DashboardTileComponent(用于呈现动态组件的占位符组件)

此组件接受来自父组件的输入,或者您可以根据您的实现从服务加载.该组件在运行时解决组件方面发挥着重要作用.在此方法中,您还可以看到名为renderComponent()的方法,该方法最终从服务加载组件名称,并使用ComponentFactoryResolver解析并最终将数据设置为动态组件.

import { Component, Input, OnInit, AfterViewInit, ViewChild, ComponentFactoryResolver, OnDestroy } from '@angular/core';
import { DashboardTileWidgetHostDirective } from './DashbardWidgetHost.Directive';
import { TileModel } from './Tile.Model';
import { WidgetComponentService } from "./WidgetComponent.Service";


@Component({
    selector: 'dashboard-tile',
    templateUrl: 'app/tile/DashboardTile.Template.html'
})

export class DashboardTileComponent implements OnInit {
    @Input() tile: any;
    @ViewChild(DashboardTileWidgetHostDirective) widgetHost: DashboardTileWidgetHostDirective;
    constructor(private _componentFactoryResolver: ComponentFactoryResolver,private widgetComponentService:WidgetComponentService) {

    }

    ngOnInit() {

    }
    ngAfterViewInit() {
        this.renderComponents();
    }
    renderComponents() {
        let component=this.widgetComponentService.getComponent(this.tile.componentName);
        let componentFactory = this._componentFactoryResolver.resolveComponentFactory(component);
        let viewContainerRef = this.widgetHost.viewContainerRef;
        let componentRef = viewContainerRef.createComponent(componentFactory);
        (<TileModel>componentRef.instance).data = this.tile;

    }
}
Run Code Online (Sandbox Code Playgroud)

DashboardTileComponent.html

 <div class="col-md-2 col-lg-2 col-sm-2 col-default-margin col-default">        
                        <ng-template widget-host></ng-template>

          </div>
Run Code Online (Sandbox Code Playgroud)

WidgetComponentService

这是一个服务工厂,用于注册要动态解析的所有组件

import { Injectable }           from '@angular/core';
import { ImageTextWidgetComponent } from "../templates/ImageTextWidget.Component";
@Injectable()
export class WidgetComponentService {
  getComponent(componentName:string) {
          if(componentName==="ImageTextWidgetComponent"){
              return ImageTextWidgetComponent
          }
  }
}
Run Code Online (Sandbox Code Playgroud)

ImageTextWidgetComponent(我们在运行时加载的组件)

import { Component, OnInit, Input } from '@angular/core';


@Component({
    selector: 'dashboard-imagetextwidget',
    templateUrl: 'app/templates/ImageTextWidget.html'
})

export class ImageTextWidgetComponent implements OnInit {
     @Input() data: any;
    constructor() { }

    ngOnInit() { }
}
Run Code Online (Sandbox Code Playgroud)

添加最后将此ImageTextWidgetComponent作为entryComponent添加到您的app模块中

@NgModule({
    imports: [BrowserModule],
    providers: [WidgetComponentService],
    declarations: [
        MainApplicationComponent,
        DashboardHostComponent,
        DashboardGroupComponent,
        DashboardTileComponent,
        DashboardTileWidgetHostDirective,
        ImageTextWidgetComponent
        ],
    exports: [],
    entryComponents: [ImageTextWidgetComponent],
    bootstrap: [MainApplicationComponent]
})
export class DashboardModule {
    constructor() {

    }
}
Run Code Online (Sandbox Code Playgroud)

TileModel

 export interface TileModel {
      data: any;
    }
Run Code Online (Sandbox Code Playgroud)

来自我博客的原始参考

官方文件

下载示例源代码


ael*_*tal 8

这个npm包让我更容易:https: //www.npmjs.com/package/ngx-dynamic-template

用法:

<ng-template dynamic-template
             [template]="'some value:{{param1}}, and some component <lazy-component></lazy-component>'"
             [context]="{param1:'value1'}"
             [extraModules]="[someDynamicModule]"></ng-template>
Run Code Online (Sandbox Code Playgroud)