At work, I was faced with the challenge of upgrading an AngularJS app with heavy use of $compile to the latest version of Angular which has no out of the box solution for compiling a template string that includes other components. So after much research I developed this component. Of course, I forked the main concept from another developer's sample posted overstack (https://stackoverflow.com/a/53739133) and I added the context input. It was hard to find on the internet, so I hope that others will benefit from this code. Enjoy.
https://mx-bind-html-compile.stackblitz.io
import {
Component, ViewChild, OnDestroy,
AfterContentInit, ComponentFactoryResolver,
Input, Compiler, ViewContainerRef, NgModule,
} from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppModule } from './app.module';
@Component({
selector: '[mxCompileHTML]',
template: `<ng-template #dynamicComponent></ng-template>`
})
export class TemplateCompileComponent implements AfterContentInit, OnDestroy {
@ViewChild('dynamicComponent', { read: ViewContainerRef }) _container: ViewContainerRef;
@Input('mxCompileHTML') template: string
@Input('mxCompileContext') context: string
private cmpRef;
constructor(
private componentFactoryResolver: ComponentFactoryResolver,
private compiler: Compiler,
) {}
ngOnDestroy() {
//Always destroy the dynamic component
//when the parent component gets destroyed
if (this.cmpRef) {
this.cmpRef.destroy();
}
}
ngAfterContentInit() {
// this code replaces this from AngualJS ---
// element.replaceWith($compile(tplContent.trim())(scope))
let context = this.context
let template = this.template
@Component({template: template})
class DynamicComponent { constructor() { Object.assign(this, context) } }
@NgModule({imports: [AppModule], declarations: [DynamicComponent]})
class DynamicComponentModule { }
const mod = this.compiler.compileModuleAndAllComponentsSync(DynamicComponentModule);
const factory = mod.componentFactories.find((comp) =>
comp.componentType === DynamicComponent
);
const component = this._container.createComponent(factory);
}
}