How to Compile Angular Component To HTML String With All The Bindings

Written by Thinkster | Published 2022/12/20
Tech Story Tags: html | angular | angular-programming | javascript | javascript-development | programming | angularjs | programming-tips

TLDRAngular doesn’t have an exposed method to compile an Angular component into an HTML string. Using `ComponentFactoryResolver` we can dynamically render the required component into a template, and then we access the `nativeElement.inner HTML` from `ComponentRef` The common use case for compiling Angular components into HTML strings are the Frontend PDF Generation with given HTML. Native JS plugins that required HTML as a string are easy to use with the use of this method. We use `import { asyncScheduler } from 'rxjs';` for getting HTML.via the TL;DR App

The common use case for compiling Angular components into HTML strings are

  • Frontend PDF Generation with given HTML
  • PRINT HTML
  • Native JS plugins that required HTML as a string.

Unfortunately Angular doesn’t have an exposed method to compile an Angular component into an HTML string. But thanks to Angular’s ComponentFactoryResolver , we can create a workaround for this. Using ComponentFactoryResolver , we can dynamically render the required component into a template, and then we access the nativeElement.innerHTML from componentRef .

One thing to note here is we have used import { asyncScheduler } from 'rxjs'; for getting HTML with all the bindings. If we are not setting this scheduler, no data binding will be available in the parse HTML.

app.component.ts

import {
  Component,
  ComponentFactory,
  ComponentFactoryResolver,
  ViewChild,
  ViewContainerRef,
} from '@angular/core';
import { asyncScheduler } from 'rxjs';
import { PdfHtmlComponent } from './pdf-html.component';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent {
  @ViewChild('pdfHtml', { read: ViewContainerRef }) container;

  constructor(private resolver: ComponentFactoryResolver) {}

  getPDFHtml() {
    this.container.clear();
    const factory: ComponentFactory<any> =
      this.resolver.resolveComponentFactory(PdfHtmlComponent);

    const componentRef = this.container.createComponent(factory);
    componentRef.instance.title = 'Injected Title';

    asyncScheduler.schedule(() => {
      const htmlString = componentRef.location.nativeElement.innerHTML;
      componentRef.destroy();
      console.log('HTML STRING:', htmlString);
    });
  }
}

app.component.html

<button (click)="getPDFHtml()">CLICK TO GET COMPONENT HTML</button>
<p>Output is in the console</p>
<div [hidden]="true">
  <template #pdfHtml></template>
</div>

pdf-html.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'pdf-html',
  templateUrl: './pdf-html.component.html',
})
export class PdfHtmlComponent {
  title: string = 'Default Title';

  STYLES: any = {
    MAIN_CONTAINER: 'background:red;',
    ITEM_BOX: 'color:red;',
  };
}

pdf-html.component.html

<h2>Title: {{ title }}</h2>

<table style="{{ STYLES.MAIN_CONTAINER }}">
  <tr style="{{ STYLES.ITEM_BOX }}">
    <th>Company</th>
    <th>Contact</th>
    <th>Country</th>
  </tr>
  <tr style="{{ STYLES.ITEM_BOX }}">
    <td>Alfreds Futterkiste</td>
    <td>Maria Anders</td>
    <td>Germany</td>
  </tr>
  <tr style="{{ STYLES.ITEM_BOX }}">
    <td>Centro comercial Moctezuma</td>
    <td>Francisco Chang</td>
    <td>Mexico</td>
  </tr>
  <tr style="{{ STYLES.ITEM_BOX }}">
    <td>Ernst Handel</td>
    <td>Roland Mendel</td>
    <td>Austria</td>
  </tr>
</table>

You can see the demo here

or you can play with the code here

Happy coding!!! 🎉🎉🎉


Written by Thinkster | Rameez AKA TheThinkster is a JavaScript enthusiast and a full stack software engineer.
Published by HackerNoon on 2022/12/20