Reputation: 23
I have a backend database containing help manual topics in html format, including anchors with on click function. My Angular (4.3.5) app has a tree of topics, when a tree topic is clicked the topic's body html is got from the backend and displayed next to the topic tree in a container div.
My question is about how to display the html page in the container div. Initially I tried:
<div [innerHtml]="htmlbody | safeHtmlPipe"></div>
This solution did not fully work because the htmlbody contains anchors to other pages as:
<a (click)="loadNewPage(topicId)">display topic</a>
Angular is sanitizing (filtering out) the anchor on click handler.
I have followed many google links on this subject like Dynamically displaying elements containing HTML with (click) functions Angular 2. Also I have looked at a wrapper component as in Dynamic Injection in Angular 4. But failed to find any actual examples of working code that specifically provides loading html from a dynamic source (ex the backend). I would like to make use of the new ngComponentOutlet directive and have it AoT compatible.
Does anyone know how to achieve this?
Upvotes: 1
Views: 625
Reputation: 23
Since no one answered this question, here is a working solution albeit it not the ideal it does work perfectly. And is AOT compliant.
Template:
<div id="pagecontainer" [innerHtml]="htmlbody | safeHtmlPipe"></div>
The following code replaces all dom anchor hrefs inside the pagecontainer with a click callback:
// use service to get backend html
this.db.get('getpage', pageId)
.subscribe(res => {
// load innerHtml with page markup
this.htmlPage = res.data;
// short pause (for template [innerHtml] = htmlbody)
setTimeout(() => {
// get all achors children of the page container
let pc = document.body.querySelector("#pagecontainer");
let x = pc.querySelectorAll('a');
Array.from(x).forEach(el => {
// get the href content
let hr = el.getAttribute('href');
if (hr != undefined) {
// replace href with onclick event
el.setAttribute('href', 'onclick=\"link()\"');
// bind click listener
el.addEventListener('click', e => {
// prevent browser precessing the anchor
e.preventDefault();
// callback with original href content
this.link(hr);
});
}
});
// scroll to the first h1
pc.getElementsByTagName('h1')[0].scrollIntoView();
this.g.showloading = false;
}, 100);
});
link(href) {
// call the topic on click handler with href to load the new page
}
And for the sake of completeness, the safeHtml pipe:
import { Pipe, PipeTransform } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
// Ref: https://stackoverflow.com/questions/39794588/angular2-innerhtml-removes-styling
@Pipe({
name: 'safeHtmlPipe'
})
export class safeHtmlPipe implements PipeTransform {
constructor(private sanitizer:DomSanitizer){}
transform(html) {
return this.sanitizer.bypassSecurityTrustHtml(html);
}
}
Upvotes: 1