change - router events angular 6
Equivalente de $ compilar en Angular 2 (7)
Angular TypeScript / ES6 (Angular 2+)
Funciona con AOT + JIT a la vez juntos.
Creé cómo usarlo aquí: https://github.com/patrikx3/angular-compile
npm install p3x-angular-compile
Componente: debe tener un contexto y algunos datos html ...
HTML:
<div [p3x-compile]="data" [p3x-compile-context]="ctx">loading ...</div>
Quiero compilar manualmente algunas directivas que contienen HTML.
¿Cuál es el equivalente de
$compile
en Angular 2?
Por ejemplo, en Angular 1, podría compilar dinámicamente un fragmento de HTML y agregarlo al DOM:
var e = angular.element(''<div directive></div>'');
element.append(e);
$compile(e)($scope);
Angular 2.3.0 (2016-12-07)
Para obtener todos los detalles, consulte:
- ¿Cómo puedo usar / crear plantillas dinámicas para compilar componentes dinámicos con Angular 2.0?
Para ver eso en acción:
- observar a un plunker en funcionamiento (trabajando con 2.3.0+)
Los principales:
1) Crear plantilla
2) Crear componente
3) Crear módulo
4) Módulo de compilación
5) Crear (y caché) ComponentFactory
6) usa Target para crear una Instancia del mismo
Una descripción rápida de cómo crear 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;
}
Una forma de inyectar componentes en 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 fragmento de código sobre cómo crear un
ComponentFactory
(y almacenarlo en caché)
public createComponentFactory(template: string)
: Promise<ComponentFactory<IHaveDynamicData>> {
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 fragmento de código sobre cómo usar el resultado anterior
// here we get Factory (just compiled or from cache)
this.typeBuilder
.createComponentFactory(template)
.then((factory: ComponentFactory<IHaveDynamicData>) =>
{
// 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 descripción completa con todos los detalles leídos aquí , u observe el ejemplo de trabajo
.
.
OBSOLETO - Angular 2.0 RC5 relacionado (solo RC5)
para ver soluciones anteriores para versiones anteriores de RC, busque en el historial de esta publicación
Para crear dinámicamente una instancia de un componente y adjuntarlo a su DOM, puede usar el siguiente script y debería funcionar en Angular RC :
plantilla html:
<div>
<div id="container"></div>
<button (click)="viewMeteo()">Meteo</button>
<button (click)="viewStats()">Stats</button>
</div>
Componente del cargador
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);
}
}
Si desea inyectar código html, use la directiva
<div [innerHtml]="htmlVar"></div>
Si desea cargar el componente completo en algún lugar, use DynamicComponentLoader:
Versión angular que he usado - Angular 4.2.0
A Angular 4 se le ocurrió ComponentFactoryResolver para cargar componentes en tiempo de ejecución. Este es un tipo de implementación de $ compile en Angular 1.0 que satisface sus necesidades
En el siguiente ejemplo, estoy cargando el componente ImageWidget dinámicamente en un DashboardTileComponent
Para cargar un componente, necesita una directiva que pueda aplicar a ng-template que le ayudará a colocar el componente dinámico
WidgetHostDirective
import { Directive, ViewContainerRef } from ''@angular/core'';
@Directive({
selector: ''[widget-host]'',
})
export class DashboardTileWidgetHostDirective {
constructor(public viewContainerRef: ViewContainerRef) {
}
}
Esta directiva inyecta ViewContainerRef para obtener acceso al contenedor de vista del elemento que alojará el componente agregado dinámicamente.
DashboardTileComponent (Coloque el componente de soporte para representar el componente dinámico)
Este componente acepta una entrada que proviene de componentes principales o puede cargar desde su servicio en función de su implementación. Este componente cumple la función principal de resolver los componentes en tiempo de ejecución. En este método también puede ver un método llamado renderComponent () que finalmente carga el nombre del componente de un servicio y lo resuelve con ComponentFactoryResolver y finalmente establece los datos en el componente dinámico.
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);
(<TileModel>componentRef.instance).data = this.tile;
}
}
DashboardTileComponent.html
<div class="col-md-2 col-lg-2 col-sm-2 col-default-margin col-default">
<ng-template widget-host></ng-template>
</div>
WidgetComponentService
Esta es una fábrica de servicios para registrar todos los componentes que desea resolver dinámicamente.
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 que estamos cargando en tiempo de ejecución)
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() { }
}
Agregar Finalmente, agregue este ImageTextWidgetComponent a su módulo de aplicación como 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;
}
este paquete npm me lo hizo más fácil: https://www.npmjs.com/package/ngx-dynamic-template
uso:
<ng-template dynamic-template
[template]="''some value:{{param1}}, and some component <lazy-component></lazy-component>''"
[context]="{param1:''value1''}"
[extraModules]="[someDynamicModule]"></ng-template>
Nota: Como @BennyBottema menciona en un comentario, DynamicComponentLoader ahora está en desuso, por lo tanto, esta respuesta también.
Angular2 no tiene ningún equivalente de
$compile
.
Puede usar
DynamicComoponentLoader
y piratear con clases ES6 para compilar su código dinámicamente (consulte este
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: ''<h1>Hello, Angular!</h1>''
})
class Hello {}
@Component({
selector: ''my-app'',
template: ''<div #container></div>'',
})
export class App implements OnInit {
constructor(
private loader: DynamicComponentLoader,
private elementRef: ElementRef,
) {}
ngOnInit() {} {
const someDynamicHtml = `<hello></hello><h2>${Date.now()}</h2>`;
this.loader.loadIntoLocation(
compileToComponent(someDynamicHtml, [Hello])
this.elementRef,
''container''
);
}
}
Pero solo funcionará hasta que el analizador html esté dentro del núcleo angular2.