Angular 2 相当于 ng-bind-html、$sce.trustAsHTML() 和 $compile?

Angular 2 equivalent of ng-bind-html, $sce.trustAsHTML(), and $compile?

在Angular1.x中,我们可以通过使用HTML标签ng-bind-html,结合[=40]实时插入HTML =] 调用 $sce.trustAsHTML()。这让我们完成了 80% 的事情,但在使用 Angular 标签时不起作用,例如如果您插入了使用 ng-repeat 或自定义指令的 HTML。

为了让它工作,我们可以使用 custom directive that called $compile.

Angular2 中所有这些的等价物是什么?我们可以使用 [inner-html] 进行绑定,但这只适用于非常简单的 HTML 标签,例如 <b>。它不会将自定义 angular 2 指令转换为功能性 HTML 元素。 (很像没有 $compile 步骤的 Angular 1.x。) Angular 2 的 $compile 是什么?

在 Angular2 中,您应该使用 DynamicComponentLoader 在页面上插入一些 "compiled content"。例如,如果你想编译下一个 html:

<div>
    <p>Common HTML tag</p>
    <angular2-component>Some angular2 component</angular2-component>
</div>

然后您需要使用此 html 作为模板创建组件(我们称之为 CompiledComponent)并使用 DynamicComponentLoader 将此组件插入页面。

@Component({
  selector: 'compiled-component'
})
@View({
  directives: [Angular2Component],
  template: `
    <div>
      <p>Common HTML tag</p>
      <angular2-component>Angular 2 component</angular2-component>
    </div>
  `
})
class CompiledComponent {
}

@Component({
  selector: 'app'
})
@View({
  template: `
    <h2>Before container</h2>
    <div #container></div>
    <h2>After conainer</h2>
  `
})
class App {
  constructor(loader: DynamicComponentLoader, elementRef: ElementRef) {
    loader.loadIntoLocation(CompiledComponent, elementRef, 'container');
  }
}

查看 this plunker

UPD 您可以在 loader.loadIntoLocation() 调用之前动态创建组件:

// ... annotations
class App {
  constructor(loader: DynamicComponentLoader, elementRef: ElementRef) {
    // template generation
    const generatedTemplate = `<b>${Math.random()}</b>`;

    @Component({ selector: 'compiled-component' })
    @View({ template: generatedTemplate })
    class CompiledComponent {};

    loader.loadIntoLocation(CompiledComponent, elementRef, 'container');
  }
}

我个人不喜欢它,对我来说它看起来像是一个肮脏的黑客。但是这里是 the plunker

PS 请注意,此时 angular2 正在积极开发中。所以情况可以随时改变。

在阅读了很多内容之后,并且即将开启一个新主题之后,我决定在这里回答,只是为了帮助其他人。正如我所见,最新版本的 Angular 2 有一些变化。(当前为 Beta9)

我会尝试分享我的代码,以避免我遇到同样的挫败感...

首先,在我们的index.html

像往常一样,我们应该有这样的东西:

<html>
 ****
  <body>
    <my-app>Loading...</my-app>
  </body>
</html>

AppComponent(使用内部HTML)

有了这个 属性 你将能够渲染基本的 HTML,但是你将无法做类似于 Angular 1.x 的事情 $通过范围编译:

import {Component} from 'angular2/core';

@Component({
    selector: 'my-app',
    template: `
                <h1>Hello my Interpolated: {{title}}!</h1>
                <h1 [textContent]="'Hello my Property bound: '+title+'!'"></h1>
                <div [innerHTML]="htmlExample"></div>
             `,
})

export class AppComponent {
    public title = 'Angular 2 app';
    public htmlExample = '  <div>' +
                                '<span [textContent]="\'Hello my Property bound: \'+title"></span>' +
                                '<span>Hello my Interpolated: {{title}}</span>' +
                            '</div>'
}

这将呈现以下内容:

Hello my Interpolated: Angular 2 app!

Hello my Property bound: Angular 2 app!

Hello my Interpolated: {{title}}

AppComponent 使用 DynamicComponentLoader

文档中有一个小错误,记录在 中。因此,如果我们牢记这一点,我的代码现在应该如下所示:

import {DynamicComponentLoader, Injector, Component, ElementRef, OnInit} from "angular2/core";

@Component({
    selector: 'child-component',
    template: `
        <div>
            <h2 [textContent]="'Hello my Property bound: '+title"></h2>
            <h2>Hello my Interpolated: {{title}}</h2>
        </div>
    `
})
class ChildComponent {
     title = 'ChildComponent title';
}

@Component({
    selector: 'my-app',
    template: `
                <h1>Hello my Interpolated: {{title}}!</h1>
                <h1 [textContent]="'Hello my Property bound: '+title+'!'"></h1>
                <div #child></div>
                <h1>End of parent: {{endTitle}}</h1>
             `,
})

export class AppComponent implements OnInit{
    public title = 'Angular 2 app';
    public endTitle= 'Bye bye!';

    constructor(private dynamicComponentLoader:DynamicComponentLoader, private elementRef: ElementRef) {
//        dynamicComponentLoader.loadIntoLocation(ChildComponent, elementRef, 'child');
    }

    ngOnInit():any {
        this.dynamicComponentLoader.loadIntoLocation(ChildComponent, this.elementRef, 'child');
    }
}

这将呈现以下内容:

Hello my Interpolated: Angular 2 app!

Hello my Property bound: Angular 2 app!

Hello my Property bound: ChildComponent title

Hello my Interpolated: ChildComponent title

End of parent: Bye bye!

Angular 提供 DynamicComponentLoader class 用于动态加载 html。 DynamicComponentLoader 有插入组件的方法。 loadIntoLocation 是其中之一用于插入组件。

paper.component.ts

import {Component,DynamicComponentLoader,ElementRef,Inject,OnInit} from 'angular2/core';
import { BulletinComponent } from './bulletin.component';

@Component({
    selector: 'paper',
    templateUrl: 'app/views/paper.html'

    }
})
export class PaperComponent {
    constructor(private dynamicComponentLoader:DynamicComponentLoader, private elementRef: ElementRef) {

    }

    ngOnInit(){
        this.dynamicComponentLoader.loadIntoLocation(BulletinComponent, this.elementRef,'child');

    }
}

bulletin.component.ts

import {Component} from 'angular2/core';

@Component({
    selector: 'bulletin',
    templateUrl: 'app/views/bulletin.html'
    }
})
export class BulletinComponent {}

paper.html

<div>
    <div #child></div>
</div>

您需要注意的几件事:

  • 不要在 class 的构造函数中调用 loadIntoLocation 。调用组件构造函数时尚未创建组件视图。你会得到错误 -

Error during instantiation of AppComponent!. There is no component directive at element [object Object]

  • 将 anchorName #child 放在 html 中,否则会出错。

Could not find variable child

DynamicComponentLoader 已弃用,您可以改用 ComponentResolver

您可以使用此指令,如果需要额外的数据操作,请添加管道。它还允许延迟加载,你不需要它,但值得一提。

指令(我找到了这段代码并做了一些修改,你也可以这样做以使其符合你的口味或按原样使用):

import { Component, Directive, ComponentFactory, ComponentMetadata, ComponentResolver, Input, ReflectiveInjector, ViewContainerRef } from '@angular/core';
declare var $:any;

export function createComponentFactory(resolver: ComponentResolver, metadata: ComponentMetadata): Promise<ComponentFactory<any>> {
    const cmpClass = class DynamicComponent {};
    const decoratedCmp = Component(metadata)(cmpClass);
    return resolver.resolveComponent(decoratedCmp);
}

@Directive({
    selector: 'dynamic-html-outlet',
})
export class DynamicHTMLOutlet {
  @Input() htmlPath: string;
  @Input() cssPath: string;

  constructor(private vcRef: ViewContainerRef, private resolver: ComponentResolver) {
  }

  ngOnChanges() {
    if (!this.htmlPath) return;
    $('dynamic-html') && $('dynamic-html').remove();
    const metadata = new ComponentMetadata({
        selector: 'dynamic-html',
        templateUrl: this.htmlPath +'.html',
        styleUrls:  [this.cssPath]
    });
    createComponentFactory(this.resolver, metadata)
      .then(factory => {
        const injector = ReflectiveInjector.fromResolvedProviders([], this.vcRef.parentInjector);
        this.vcRef.createComponent(factory, 0, injector, []);
      });
  }
}

使用示例:

import { Component, OnInit } from '@angular/core';
import { DynamicHTMLOutlet } from './../../directives/dynamic-html-outlet/dynamicHtmlOutlet.directive';

@Component({
  selector: 'lib-home',
  templateUrl: './app/content/home/home.component.html',
  directives: [DynamicHTMLOutlet]
})
export class HomeComponent implements OnInit{
    html: string;
    css: string;

    constructor() {}

    ngOnInit(){
    this.html = './app/content/home/home.someTemplate.html';
    this.css = './app/content/home/home.component.css';
    }

  }

home.component.html:

<dynamic-html-outlet [htmlPath]="html" [cssPath]="css"></dynamic-html-outlet>

看看这个模块https://www.npmjs.com/package/ngx-dynamic-template

经过长时间的研究,只有这件事对我有帮助。其余解决方案似乎已过时。

我想你所要做的就是用 [innerHTML]="yourcomponentscopevar"

设置你想要编译的元素 html