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

时间:2015-09-01 20:48:30

标签: innerhtml angular

在Angular 1.x中,我们可以使用HTML标记ng-bind-html并结合JavaScript调用$sce.trustAsHTML()实时插入HTML。这使我们有80%的时间,但在使用Angular标签时不会起作用,例如插入使用ng-repeat或自定义指令的HTML。

为了实现这一点,我们可以使用custom directive that called $compile

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

6 个答案:

答案 0 :(得分:11)

In Angular2 you should use DynamicComponentLoader to insert some "compiled content" on the page. So for example if you want to compile next html:

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

then you need to create component with this html as a template (let's call it CompiledComponent) and use DynamicComponentLoader to insert this component on the page.

@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');
  }
}

Check out this plunker

UPD You can create component dynamically right before the loader.loadIntoLocation() call:

// ... 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');
  }
}

I personally don't like it, it's look like a dirty hack to me. But here is the plunker

PS Beware that at this moment angular2 is under active development. So situation can be changed at any time.

答案 1 :(得分:5)

不推荐使用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>

答案 2 :(得分:3)

在阅读了很多内容并接近开启一个新主题后,我决定回答这里只是为了试图帮助其他人。我已经看到Angular 2的最新版本有几处变化。(目前是Beta9)

我会尝试分享我的代码,以避免同样的挫折......

首先,在我们的index.html中

像往常一样,我们应该有这样的事情:

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

AppComponent(使用innerHTML)

使用此属性,您将能够呈现基本HTML,但您无法通过范围执行类似于Angular 1.x和$ compile的操作:

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 in Interpolated:Angular 2 app!

     

Hello my Property bound:Angular 2 app!

     

您好我的插值:{{title}}

AppComponent使用DynamicComponentLoader

here中记录了文档的一个小错误。因此,如果我们记住这一点,我的代码现在看起来应该是这样的:

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 in Interpolated:Angular 2 app!

     

Hello my Property bound:Angular 2 app!

     

Hello我的属性绑定:ChildComponent标题

     

您好我的Interpolated:ChildComponent标题

     

父母结束:再见!

答案 3 :(得分:2)

我认为您所要做的就是使用[innerHTML] =“yourcomponentscopevar”设置要编译html的元素

答案 4 :(得分:0)

Angular提供DynamicComponentLoader类动态加载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>

您需要处理的事情很少:

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

AppComponent实例化期间出错!没有组件   元素[object Object]

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

无法找到变量子

答案 5 :(得分:0)

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

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