Equivalente di $ compile in Angular 2

Voglio compilare manualmente alcune direttive contenenti HTML. Qual è l’equivalente di $compile in Angular 2?

Ad esempio, in Angular 1, potrei compilare dynamicmente un frammento di HTML e aggiungerlo al DOM:

 var e = angular.element('
'); element.append(e); $compile(e)($scope);

Angular 2.3.0 (2016-12-07)

Per controllare tutti i dettagli:

  • Come posso usare / creare template dinamico per compilare componenti dinamici con Angular 2.0?

Per vederlo in azione:

  • osservare un plunker funzionante (funzionante con 2.3.0+)

I principali:

1) Crea modello
2) Crea componente
3) Crea modulo
4) Modulo di compilazione
5) Creare (e memorizzare) ComponentFactory
6) usa Target per creare un’Istanza di esso

Una breve panoramica su come creare un componente

 createNewComponent (tmpl:string) { @Component({ selector: 'dynamic-component', template: tmpl, }) class CustomDynamicComponent implements IHaveDynamicData { @Input() public entity: any; }; // a component for this particular template return CustomDynamicComponent; } 

Un modo per iniettare componenti in NgModule

 createComponentModule (componentType: any) { @NgModule({ imports: [ PartsModule, // there are 'text-editor', 'string-editor'... ], declarations: [ componentType ], }) class RuntimeComponentModule { } // a module for just this Type return RuntimeComponentModule; } 

Un frammento di codice su come creare un ComponentFactory (e salvarlo nella cache)

 public createComponentFactory(template: string) : Promise> { let factory = this._cacheOfFactories[template]; if (factory) { console.log("Module and Type are returned from cache") return new Promise((resolve) => { resolve(factory); }); } // unknown template ... let's create a Type for it let type = this.createNewComponent(template); let module = this.createComponentModule(type); return new Promise((resolve) => { this.compiler .compileModuleAndAllComponentsAsync(module) .then((moduleWithFactories) => { factory = _.find(moduleWithFactories.componentFactories , { componentType: type }); this._cacheOfFactories[template] = factory; resolve(factory); }); }); } 

Un frammento di codice come utilizzare il risultato sopra

  // here we get Factory (just compiled or from cache) this.typeBuilder .createComponentFactory(template) .then((factory: ComponentFactory) => { // Target will instantiate and inject component (we'll keep reference to it) this.componentRef = this .dynamicComponentTarget .createComponent(factory); // let's inject @Inputs to component instance let component = this.componentRef.instance; component.entity = this.entity; //... }); 

La descrizione completa con tutti i dettagli letti qui , o osservare l’ esempio di lavoro

.

.

OBSOLETE – Correlato per Angular 2.0 RC5 (solo RC5)

per vedere le soluzioni precedenti per le versioni precedenti di RC, per favore, cerca nella cronologia di questo post

Nota: Come @BennyBottema menziona in un commento, DynamicComponentLoader è ora deprecato, quindi questa è la risposta.


Angular2 non ha alcun equivalente $ compile . Puoi utilizzare DynamicComoponentLoader e hackerare con le classi ES6 per compilare il tuo codice dynamicmente (vedi questo plunk ):

 import {Component, DynamicComponentLoader, ElementRef, OnInit} from 'angular2/core' function compileToComponent(template, directives) { @Component({ selector: 'fake', template , directives }) class FakeComponent {}; return FakeComponent; } @Component({ selector: 'hello', template: '

Hello, Angular!

' }) class Hello {} @Component({ selector: 'my-app', template: '
', }) export class App implements OnInit { constructor( private loader: DynamicComponentLoader, private elementRef: ElementRef, ) {} ngOnInit() {} { const someDynamicHtml = `

${Date.now()}

`; this.loader.loadIntoLocation( compileToComponent(someDynamicHtml, [Hello]) this.elementRef, 'container' ); } }

Ma funzionerà solo fino a quando il parser html è all’interno del core angular2.

Versione angular che ho usato – Angular 4.2.0

Angular 4 è uscito con ComponentFactoryResolver per caricare i componenti in fase di esecuzione. Questo è un tipo di stessa implementazione di $ compilare in Angular 1.0 che soddisfa le tue necessità

Nel seguente esempio sto caricando dynamicmente il componente ImageWidget in un DashboardTileComponent

Per caricare un componente hai bisogno di una direttiva che puoi applicare a ng-template che ti aiuterà a posizionare il componente dinamico

WidgetHostDirective

  import { Directive, ViewContainerRef } from '@angular/core'; @Directive({ selector: '[widget-host]', }) export class DashboardTileWidgetHostDirective { constructor(public viewContainerRef: ViewContainerRef) { } } 

questa direttiva inietta ViewContainerRef per accedere al contenitore della vista dell’elemento che ospiterà il componente aggiunto dynamicmente.

DashboardTileComponent (posiziona il componente titolare per il rendering del componente dinamico)

Questo componente accetta un input che proviene da un componente padre o che è ansible caricare dal servizio in base all’implementazione. Questo componente sta svolgendo il ruolo principale per risolvere i componenti in fase di runtime. In questo metodo è anche ansible visualizzare un metodo denominato renderComponent () che in ultima analisi carica il nome del componente da un servizio e risolve con ComponentFactoryResolver e infine imposta i dati al componente dinamico.

 import { Component, Input, OnInit, AfterViewInit, ViewChild, ComponentFactoryResolver, OnDestroy } from '@angular/core'; import { DashboardTileWidgetHostDirective } from './DashbardWidgetHost.Directive'; import { TileModel } from './Tile.Model'; import { WidgetComponentService } from "./WidgetComponent.Service"; @Component({ selector: 'dashboard-tile', templateUrl: 'app/tile/DashboardTile.Template.html' }) export class DashboardTileComponent implements OnInit { @Input() tile: any; @ViewChild(DashboardTileWidgetHostDirective) widgetHost: DashboardTileWidgetHostDirective; constructor(private _componentFactoryResolver: ComponentFactoryResolver,private widgetComponentService:WidgetComponentService) { } ngOnInit() { } ngAfterViewInit() { this.renderComponents(); } renderComponents() { let component=this.widgetComponentService.getComponent(this.tile.componentName); let componentFactory = this._componentFactoryResolver.resolveComponentFactory(component); let viewContainerRef = this.widgetHost.viewContainerRef; let componentRef = viewContainerRef.createComponent(componentFactory); (componentRef.instance).data = this.tile; } } 

DashboardTileComponent.html

  

WidgetComponentService

Questa è una fabbrica di servizi per registrare tutti i componenti che si desidera risolvere in modo dinamico

 import { Injectable } from '@angular/core'; import { ImageTextWidgetComponent } from "../templates/ImageTextWidget.Component"; @Injectable() export class WidgetComponentService { getComponent(componentName:string) { if(componentName==="ImageTextWidgetComponent"){ return ImageTextWidgetComponent } } } 

ImageTextWidgetComponent (componente che stiamo caricando in fase di runtime)

 import { Component, OnInit, Input } from '@angular/core'; @Component({ selector: 'dashboard-imagetextwidget', templateUrl: 'app/templates/ImageTextWidget.html' }) export class ImageTextWidgetComponent implements OnInit { @Input() data: any; constructor() { } ngOnInit() { } } 

Aggiungi Infine aggiungi questo ImageTextWidgetComponent al modulo dell’app come entryComponent

 @NgModule({ imports: [BrowserModule], providers: [WidgetComponentService], declarations: [ MainApplicationComponent, DashboardHostComponent, DashboardGroupComponent, DashboardTileComponent, DashboardTileWidgetHostDirective, ImageTextWidgetComponent ], exports: [], entryComponents: [ImageTextWidgetComponent], bootstrap: [MainApplicationComponent] }) export class DashboardModule { constructor() { } } 

TileModel

  export interface TileModel { data: any; } 

Riferimento originale dal mio blog

Documentazione ufficiale

Scarica il codice sorgente di esempio

questo pacchetto npm ha reso tutto più facile per me: https://www.npmjs.com/package/ngx-dynamic-template

utilizzo:

  

Per creare dynamicmente un’istanza di un componente e collegarlo al tuo DOM puoi usare il seguente script e lavorare in Angular RC :

modello html:

 

Componente caricatore

 import { Component, DynamicComponentLoader, ElementRef, Injector } from '@angular/core'; import { WidgetMeteoComponent } from './widget-meteo'; import { WidgetStatComponent } from './widget-stat'; @Component({ moduleId: module.id, selector: 'widget-loader', templateUrl: 'widget-loader.html', }) export class WidgetLoaderComponent { constructor( elementRef: ElementRef, public dcl:DynamicComponentLoader, public injector: Injector) { } viewMeteo() { this.dcl.loadAsRoot(WidgetMeteoComponent, '#container', this.injector); } viewStats() { this.dcl.loadAsRoot(WidgetStatComponent, '#container', this.injector); } } 

Angular TypeScript / ES6 (Angular 2+)

Funziona con AOT + JIT contemporaneamente.

Ho creato come usarlo qui: https://github.com/patrikx3/angular-compile

 npm install p3x-angular-compile 

Componente: dovrebbe avere un contesto e alcuni dati html …

html:

 
loading ...

Se si desidera inserire la direttiva per l’uso del codice html

 

Se vuoi caricare l’intero componente in qualche posto, usa DynamicComponentLoader:

https://angular.io/docs/ts/latest/api/core/DynamicComponentLoader-class.html