Angulaire équivalent de 2 ng-bind-html, $sec.trustAsHTML (), et $ compiler?

En Angle 1.x, nous pourrions insérer du HTML en temps réel en utilisant la balise HTML ng-bind-html , combinée avec L'appel JavaScript $sce.trustAsHTML() . Cela nous a permis d'atteindre 80% de cet objectif, mais ne fonctionnerait pas lorsque des balises angulaires étaient utilisées, comme si vous insériez HTML qui utilisait ng-repeat ou des directives personnalisées.

pour que cela fonctionne, nous pourrions utiliser une directive personnalisée qui appelle $compile .

Quel est l'équivalent pour tous les C'est en angle 2? Nous pouvons lier en utilisant [inner-html] mais cela ne fonctionne que pour des balises HTML très simples telles que <b> . Il ne transforme pas les directives personnalisées angular 2 en éléments HTML fonctionnels. (Un peu comme Angular 1.x Sans l'étape $compile .) Quel est l'équivalent de $compile Angulaire 2?

16
demandé sur Community 2015-09-01 23:48:30

6 réponses

dans Angular2 vous devez utiliser DynamicComponentLoader pour insérer un peu de" contenu compilé " sur la page. Par exemple, si vous voulez compiler le prochain html:

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

ensuite, vous devez créer le composant avec ce html comme modèle (appelons-le CompiledComponent ) et utiliser DynamicComponentLoader pour insérer ce composant sur la 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 vous pouvez créer un composant dynamiquement juste avant l'appel 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');
  }
}

personnellement, je n'aime pas ça, ça ressemble à un sale piratage pour moi. Mais voici le plongeur

PS attention, angular2 est actuellement en développement. La situation peut donc être changée à tout moment.

11
répondu alexpods 2015-09-03 17:39:57

DynamicComponentLoader est déprécié, vous pouvez utiliser ComponentResolver à la place

vous pouvez utiliser cette directive, ajouter des pipes si vous avez besoin de manipulation de données supplémentaires. Il permet également le chargement paresseux, vous n'en avez pas besoin dans votre cas, mais il est intéressant de mentionner.

Directive (j'ai trouvé ce code et j'ai fait quelques modifications, vous pouvez le faire aussi pour qu'il corresponde à votre goût ou l'utiliser tel quel):

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, []);
      });
  }
}

exemple d'utilisation:

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

  }

à la maison.composant.html:

<dynamic-html-outlet [htmlPath]="html" [cssPath]="css"></dynamic-html-outlet>
5
répondu Daniel abzakh 2016-09-11 01:35:37

après avoir beaucoup lu, et étant proche d'ouvrir un nouveau sujet, j'ai décidé de répondre ici juste pour essayer d'aider les autres. Comme je l'ai vu, il y a plusieurs changements avec la dernière version D'Angular 2. (Actuellement Beta9)

je vais essayer de partager mon code afin d'éviter la même frustration que j'ai eue...

premier, dans notre index.html

comme d'habitude, nous devrions avoir quelque chose comme ceci:

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

AppComponent (using innerHTML)

avec cette propriété vous serez en mesure de rendre le HTML de base, mais vous ne serez pas en mesure de faire quelque chose de similaire à Angular 1.X comme $ compiler à travers un scope:

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

ce qui donnera le résultat suivant:

Bonjour, mon Interpolée: Angulaire 2 app!

Bonjour ma Propriété lié: Angulaire 2 app!

Bonjour, mon Interpolée: {{titre}}

AppComponent Using DynamicComponentLoader

il y a un petit bug avec les docs, documenté dans ici . Donc, si nous avons à l'esprit que, mon code devrait regardez maintenant comme ceci:

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

ce qui donnera le résultat suivant:

Bonjour mon Interpolée: Angulaire 2 app!

Bonjour ma Propriété lié: Angulaire 2 app!

Bonjour ma Propriété lié: ChildComponent titre

Bonjour, mon Interpolée: ChildComponent titre

fin de parent: Bye bye!

3
répondu Jesús Sobrino 2017-05-23 12:26:07

je pense que tout ce que vous avez à faire est de définir l'élément que vous voulez avoir compilé html avec le [innerHTML]= "votrecomponentscopevar "

2
répondu Gregory Edwards 2018-04-04 14:04:35

Angulaire fournis DynamicComponentLoader classe pour le chargement html dynamiquement. DynamicComponentLoader comporte des méthodes d'insertion de composants. loadIntoLocation est l'un d'eux pour insérer le composant.

papier.composant.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.composant.ts

import {Component} from 'angular2/core';

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

papier.html

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

peu de choses dont vous avez besoin pour s'occuper de:

  • Ne pas appeler loadIntoLocation à l'intérieur du constructeur de la classe . Component view n'est pas encore créé lorsque component constructor est appelé. Vous obtiendrez erreur -

erreur lors de l'instanciation D'un AppComponent!. Il n'y a pas de composant la directive de l'élément [object object]

  • mettez anchornname #child en html sinon vous obtiendrez erreur.

impossible de trouver la variable d'enfant

0
répondu Anshul 2016-03-22 09:58:24

Regardez ce module https://www.npmjs.com/package/ngx-dynamic-template

après une longue recherche, seule cette chose m'a aidé. Les autres solutions semblent dépassées.

0
répondu nostop 2017-12-08 14:22:16