Render Angular Components in Markdown
Dharmen Shah
Posted on July 5, 2024
This example demonstrates renderring of markdown in angular and also how to render angular components in markdown.
First, we will setup <markdown-render>
component to render .md
files. And then we will look how to render angular components.
Markdown Renderer
Install needed dependencies:
npm i highlight.js marked marked-highlight
Step 1: Create markdown-renderer/highlight-code-block.ts
This function will be used to highlight code in our markdown file
import highlightJs from 'highlight.js';
export function highlightCodeBlock(code: string, language: string | undefined) {
if (language) {
return highlightJs.highlight(code, {
language,
}).value;
}
return code;
}
Step 2: Create markdown-renderer/transform-markdown.ts
This function will be used to convert markdown to html.
import { marked } from 'marked';
import { markedHighlight } from 'marked-highlight';
import { highlightCodeBlock } from './highlight-code-block';
marked.use(markedHighlight({ highlight: highlightCodeBlock }));
export const markdownToHtml = (content: string) => {
return marked(content);
};
Step 3: Create markdown-renderer/markdown.service.ts
This service will be used in the component to read .md
file from local or external location and then convert it to html.
import { HttpClient } from '@angular/common/http';
import { Injectable, inject } from '@angular/core';
import { map } from 'rxjs';
import { markdownToHtml } from './transform-markdown';
@Injectable({
providedIn: 'root',
})
export class MarkdownService {
private httpClient = inject(HttpClient);
htmlContent(src: string) {
return this.httpClient.get(src, { responseType: 'text' }).pipe(
map((markdownContent) => {
return markdownToHtml(markdownContent);
})
);
}
}
Step 4: Create markdown-renderer/markdown-renderer.ts
Finally, this will be out component which we can use to render markdown files.
import { Component, ElementRef, effect, inject, input } from '@angular/core';
import { MarkdownService } from './markdown.service';
import { take } from 'rxjs';
import highlightJs from 'highlight.js';
@Component({
selector: 'markdown-renderer',
template: 'Loading document...',
standalone: true,
})
export class MarkdownRendererComponent {
src = input.required<string>();
textContent = '';
private _elementRef = inject<ElementRef>(ElementRef);
private markdownService = inject(MarkdownService);
constructor() {
effect(() => {
const src = this.src();
this.setDataFromSrc(src);
});
}
setDataFromSrc(src: string) {
this.markdownService
.htmlContent(src)
.pipe(take(1))
.subscribe((htmlContent) => {
this.updateDocument(htmlContent as string);
});
}
updateDocument(rawHTML: string) {
this._elementRef.nativeElement.innerHTML = rawHTML;
this.textContent = this._elementRef.nativeElement.textContent;
highlightJs.highlightAll();
}
}
Step 5: Provide HTTP
bootstrapApplication(App, {
providers: [
provideHttpClient(withFetch())
],
});
Step 6: Usage
Now, wherever we want to render markdown, we will simply use <markdown-renderer>
:
import { Component } from '@angular/core';
import { MarkdownRendererComponent } from './markdown-renderer/markdown-renderer';
@Component({
selector: 'article',
standalone: true,
template: `<markdown-renderer src="/assets/article.md"></markdown-renderer>`,
imports: [MarkdownRendererComponent],
})
export class ArticleComponent {}
Angular Components in Markdown
Install needed dependencies:
npm i @angular/elements
Step 1: Create custom-elements.service.ts
This service will used to convert angular components to custom elements, so that we can easily use angular components in in .md
file.
import { inject, Injectable, Injector } from '@angular/core';
import { createCustomElement } from '@angular/elements';
import { SubscribeComponent } from './components/subscribe';
import { CounterComponent } from './components/counter';
@Injectable({ providedIn: 'root' })
export class CustomElementsService {
private _injector = inject(Injector);
setupCustomElements() {
const subscribeElement = createCustomElement(SubscribeComponent, {
injector: this._injector,
});
customElements.define('subscribe-component', subscribeElement);
const counterElement = createCustomElement(CounterComponent, {
injector: this._injector,
});
customElements.define('counter-component', counterElement);
}
}
Step 2: Call setupCustomElements
through APP_INITIALIZER
As we want custom elements present from the initialization, we will use APP_INITIALIZER
.
bootstrapApplication(App, {
providers: [
provideHttpClient(withFetch()),
{
provide: APP_INITIALIZER,
useFactory: initializeCustomElements,
multi: true,
deps: [CustomElementsService],
},
],
});
Step 3: Usage
Finally, you can simply use your custom element in .md
file it will render the angular component, like below:
<subscribe-component></subscribe-component>
<counter-component></counter-component>
Code
Support free content creation
Even though the courses and articles are available at no cost, your support in my endeavor to deliver top-notch educational content would be highly valued. Your decision to contribute aids me in persistently improving the course, creating additional resources, and maintaining the accessibility of these materials for all. I'm grateful for your consideration to contribute and make a meaningful difference!
Posted on July 5, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.