Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
A directive to dynamically compile HTML. Source: https://plnkr.co/edit/mcvILwmOLvrS2PxIrXX8?p=preview
import {
Component,
Directive,
NgModule,
Input,
ViewContainerRef,
Compiler,
ComponentFactory,
ModuleWithComponentFactories,
ComponentRef,
ReflectiveInjector
} from '@angular/core';
import { RouterModule } from '@angular/router';
import { CommonModule } from '@angular/common';
export function createComponentFactory(compiler: Compiler, metadata: Component): Promise<ComponentFactory<any>> {
const cmpClass = class DynamicComponent {};
const decoratedCmp = Component(metadata)(cmpClass);
@NgModule({ imports: [CommonModule, RouterModule], declarations: [decoratedCmp] })
class DynamicHtmlModule { }
return compiler.compileModuleAndAllComponentsAsync(DynamicHtmlModule)
.then((moduleWithComponentFactory: ModuleWithComponentFactories<any>) => {
return moduleWithComponentFactory.componentFactories
.find(x => x.componentType === decoratedCmp);
});
}
@Directive({
selector: 'client-html-outlet',
})
export class ClientHtmlOutletDirective {
@Input() html: string;
cmpRef: ComponentRef<any>;
constructor(private vcRef: ViewContainerRef, private compiler: Compiler) { }
ngOnChanges() {
const html = this.html;
if (!html) return;
if (this.cmpRef) {
this.cmpRef.destroy();
}
const compMetadata = new Component({
selector: 'dynamic-html',
template: this.html,
});
createComponentFactory(this.compiler, compMetadata).then(factory => {
const injector = ReflectiveInjector.fromResolvedProviders([], this.vcRef.parentInjector);
this.cmpRef = this.vcRef.createComponent(factory, 0, injector, []);
});
}
ngOnDestroy() {
if (this.cmpRef) {
this.cmpRef.destroy();
}
}
}
@jesteross

This comment has been minimized.

Copy link

@jesteross jesteross commented Nov 21, 2017

Hi Benjamin
I use your html outlet directive in my project.
Thank you a lot for this!

Could you please explain me one thing
If dynamic html will contain some methods
<a (click)='onClick()'>home

Do I have possibility to predefine and describe this method somewhere in APP?

Thanks!

@benjamincharity

This comment has been minimized.

Copy link
Owner Author

@benjamincharity benjamincharity commented May 23, 2019

Sorry, I never saw this comment..

I haven't had the need for dynamic component generation in quite some time so I'm a bit outdated on this side of things. Possibly something like this could work. https://stackoverflow.com/a/49038739/722367 … Basically use the reference once you create the component to dynamically add methods/functionality

@chxylucy

This comment has been minimized.

Copy link

@chxylucy chxylucy commented May 28, 2019

Hi Benjamin
I use your html outlet directive in my project.
Thank you a lot for this!

Could you please explain me one thing
If dynamic html will contain some methods
<a (click)='onClick()'>home

Do I have possibility to predefine and describe this method somewhere in APP?

Thanks!

See my updated code here

https://stackoverflow.com/questions/56279217/angular-dynamic-html-template-component-with-event-emitter/

inside the dynamic html you can pass an event trigger string back to the parent component to throw into a switch in order to control the behaviour

inside the dynamic html use

(click)="genEmit('pass back to parent')

inside the parent that holds the outlet

you can capture the emitted event

<html-outlet [html]="tableHTMLOutput" (genericEmitter)="captureEvent($event)" ></html-outlet>

@Oztrea

This comment has been minimized.

Copy link

@Oztrea Oztrea commented Sep 23, 2020

I'm trying to use your directive to include a mvc partial view in my angular. But it doesn't work with Angular 10. Any Idea what's wrong?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment