innerhtml angular

innerhtml - ¿Equivalente angular 2 de ng-bind-html, $ sce.trustAsHTML() y $ compile?



(6)

Angular proporcionó la clase DynamicComponentLoader para cargar html dinámicamente. DynamicComponentLoader tiene métodos para insertar componentes. loadIntoLocation es uno de ellos para insertar componentes.

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>

Pocas cosas que debe cuidar:

  • No llame a loadIntoLocation dentro del constructor de la clase. La vista de componentes aún no se crea cuando se llama al constructor de componentes. Recibirá un error.

¡Error durante la instanciación de AppComponent !. No hay directiva de componente en el elemento [objeto Objeto]

  • Coloque anchorName #child en html; de lo contrario, obtendrá un error.

No se pudo encontrar el hijo variable

En Angular 1.x, podríamos insertar HTML en tiempo real usando la etiqueta HTML ng-bind-html , combinada con la llamada de JavaScript $sce.trustAsHTML() . Esto nos llevó al 80% del camino hasta allí, pero no funcionaría cuando se usaran etiquetas angulares, como si insertara HTML que usara ng-repeat o directivas personalizadas.

Para que eso funcione, podríamos usar una directiva personalizada que se llama $ compilar .

¿Cuál es el equivalente de todo esto en Angular 2? Podemos enlazar usando [inner-html] pero esto solo funciona para etiquetas HTML muy simples como <b> . No transforma las directivas angulares 2 personalizadas en elementos HTML funcionales. (Al igual que Angular 1.x sin el paso de $compile .) ¿Cuál es el equivalente de $compile de $compile para Angular 2?


Creo que todo lo que tiene que hacer es establecer el elemento que desea compilar html con [innerHTML] = "yourcomponentscopevar"


Después de leer mucho y de estar cerca de abrir un nuevo tema, decidí responder aquí solo para tratar de ayudar a los demás. Como he visto, hay varios cambios con la última versión de Angular 2. (Actualmente Beta9)

Intentaré compartir mi código para evitar la misma frustración que tuve ...

Primero, en nuestro index.html

Como de costumbre, deberíamos tener algo como esto:

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

AppComponent (usando innerHTML)

Con esta propiedad podrá renderizar el HTML básico, pero no podrá hacer algo similar a Angular 1.x como $ compile a través de un ámbito:

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

Esto generará lo siguiente:

Hola, mi aplicación Interpolated: Angular 2.

Hola mi propiedad vinculada: aplicación Angular 2!

Hola mi interpolado: {{title}}

AppComponent con DynamicComponentLoader

Hay un pequeño error con los documentos, documentado here . Entonces, si tenemos en cuenta eso, mi código debería verse así:

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

Esto generará lo siguiente:

Hola, mi aplicación Interpolated: Angular 2.

Hola mi propiedad vinculada: aplicación Angular 2!

Hola mi propiedad vinculada: Título de ChildComponent

Hola mi título Interpolated: ChildComponent

Fin de los padres: ¡Adiós!


DynamicComponentLoader está en desuso, puede usar ComponentResolver en su lugar

Puede usar esta directiva, agregar tuberías si necesita manipulación de datos adicional. También permite la carga diferida, no lo necesita en su caso, pero vale la pena mencionarlo.

Directiva (encontré este código e hice algunos cambios, también puedes hacerlo para que se ajuste a tu gusto o usarlo como está):

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

Ejemplo de cómo usarlo:

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>



En Angular2 debe usar DynamicComponentLoader para insertar "contenido compilado" en la página. Entonces, por ejemplo, si desea compilar el siguiente html:

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

entonces necesita crear un componente con este html como plantilla (llamémoslo CompiledComponent ) y usar DynamicComponentLoader para insertar este componente en la página.

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

Mira este saqueador

UPD Puede crear componentes dinámicamente justo antes de la llamada 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''); } }

Personalmente no me gusta, me parece un truco sucio. Pero aquí está el saqueador

PD: Tenga en cuenta que en este momento angular2 está en desarrollo activo. Entonces la situación se puede cambiar en cualquier momento.