web-dev-qa-db-ja.com

Angular ng-bind-html、$ sce.trustAsHTML()、および$ compileの2つの同等物?

Angular 1.xでは、HTMLタグ_ng-bind-html_をJavaScript呼び出し$sce.trustAsHTML()と組み合わせて使用​​することで、リアルタイムでHTMLを挿入できました。これにより80%の道が開けましたが、_ng-repeat_またはカスタムディレクティブを使用するHTMLを挿入した場合など、Angularタグが使用されている場合は機能しません。

これを機能させるには、 $ compileを呼び出すカスタムディレクティブ を使用できます。

Angular 2のこのすべてに相当するものは何ですか? _[inner-html]_を使用してバインドできますが、これは_<b>_などの非常に単純なHTMLタグでのみ機能します。カスタムangular 2ディレクティブを機能するHTML要素に変換しません。 (Angular 1.xの_$compile_ステップなしのように。)Angular 2の_$compile_と同等のものは何ですか?

16
Vern Jensen

Angular2では、 DynamicComponentLoader を使用して、ページに「コンパイル済みコンテンツ」を挿入する必要があります。たとえば、次の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');
  }
}
_

私は個人的にそれが好きではありません、それは私にとって汚いハックのように見えます。しかし、ここに 配管工

[〜#〜] ps [〜#〜]この時点で、angular2が活発に開発されていることに注意してください。したがって、状況はいつでも変更できます。

11
alexpods

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>
5
Daniel abzakh

よく読んで、新しいトピックを開くことに近づいたので、他の人を助けるためだけにここで答えることにしました。私が見たように、Angular 2.(現在はBeta9)の最新バージョンでいくつかの変更があります。

私が持っていた同じ欲求不満を避けるために、コードを共有しようとします...

まず、index.html

いつものように、次のようなものが必要です。

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

AppComponent(innerHTMLを使用)

このプロパティを使用すると、基本的なHTMLをレンダリングできますが、スコープを介して$ compileとして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>'
}

これにより、以下がレンダリングされます。

こんにちは私の補間:Angular 2アプリ!

こんにちは、プロパティのバインド:Angular 2 app!

こんにちは私の補間:{{title}}

DynamicComponentLoaderを使用したAppComponent

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

これにより、以下がレンダリングされます。

こんにちは私の補間:Angular 2アプリ!

こんにちは、プロパティのバインド:Angular 2 app!

Helloバインドされたプロパティ:ChildComponentタイトル

こんにちは、Interpolated:ChildComponentタイトル

親の終わり:さようなら!

3
Jesús Sobrino

あなたがしなければならないことは、HTMLをコンパイルしたい要素を[innerHTML] = "yourcomponentscopevar"で設定することだけだと思います

1
Gregory Edwards

このモジュールをご覧ください https://www.npmjs.com/package/ngx-dynamic-template

長い研究の後、このことだけが私を助けました。残りのソリューションは時代遅れのようです。

0
nostop

Angularはhtmlを動的にロードするDynamicComponentLoaderクラスを提供しました。 DynamicComponentLoaderには、コンポーネントを挿入するためのメソッドがあります。 loadIntoLocationはコンポーネントを挿入するためのそれらの1つです。

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を呼び出さないでください。コンポーネントコンストラクターが呼び出されたとき、コンポーネントビューはまだ作成されていません。エラーが発生します-

AppComponent!のインスタンス化中にエラーが発生しました。要素[object Object]にはコンポーネントディレクティブがありません

  • AnchorName #childをhtmlに入れると、エラーが発生します。

変数の子が見つかりませんでした

0
Anshul