0

My html content is generated by a markdown compiler in the backend, and what I want angular to do is to get data from server, dynamically render the content and display.

The mock markdown content may be things like this:

<h1 id="test1">Test 1<a href="#test1" title="Permanent link">&para;</a></h1>
<h1 id="test2">Test 2<a href="#test2" title="Permanent link">&para;</a></h1>

In foo.component.html, I use innerHTML attribute to display contents, like this:

<div [innerHTML]="mock_markdown_content"></div>

Now, the link on those anchor tags will become things like localhost:4200/#test1, and cannot navigate to the location of these elements as expected.

Since the html content is generated by markdown compiler, I don't want to change the html content itself.

Actually, the url link that this foo.component will be displayed in browser is something like localhost:4200/post/post-title, so the expected url of these anchor tags are localhost:4200/post/post-title#test1.

I found that the official guide of Angular can do what exactly I want, like this: https://angular.io/guide/router#overview (correctly display the url and can navigate to the element position). How do they implement this?

funkid
  • 577
  • 1
  • 10
  • 30
  • Some or the other way you need to change your href links. My suggestion is to save the current route in your component, either by listening to route changes event or `window.location.href` and modify `href` attribute by accessing the dom elements. – Amit Chigadani May 18 '19 at 14:13
  • @AmitChigadani You mean change the href in typescript is the only way? Actually I found that the official guide of Angular can do what I exactly want, like this: https://angular.io/guide/router#overview (correctly display the url and can navigate to the element position) how do they implement? – funkid May 18 '19 at 14:21
  • What your backend is sending to you as `href`? Is it `localhost:4200/#test1` or `#test1` – Amit Chigadani May 18 '19 at 14:49
  • @AmitChigadani my backend sends me the content that compiled from markdown to html, so it is just things like this:`

    Test 1

    `, and when I move onto the link in Angular's rendered html, it shows `localhost:4200/#test1`
    – funkid May 18 '19 at 14:55
  • 1
    You can try the solution given in [this answer](https://stackoverflow.com/a/53049231/1009922). It seems to work, as shown in [this stackblitz](https://stackblitz.com/edit/angular-8c5a9r?file=src%2Fapp%2Fapp.component.html). – ConnorsFan May 18 '19 at 15:01
  • @ConnorsFan Thanks, but it seems that I have to manually change the `routerLink` and add `fragment` attribute to all anchor tags? Since the html content is generated by my backend automatically, is there another better way to implement this without doing this? Or is changing `routerLink` and `fragment` the only way? Does official angular guide (like this: https://angular.io/guide/router#overview) implement this feature also by this way? – funkid May 18 '19 at 15:06
  • @funkid You need to modify `anchor` tag either in the UI or server side. Without which, you will not be able to achieve what you want. – Amit Chigadani May 18 '19 at 15:16
  • @AmitChigadani Thanks, if that's the only way, I would like to change `anchor` tag in Angular. Would you please tell me if there is a way or built-in function to get and modify all these `anchor` tags in typescript? (The whole html content is stored in a variable in string type.) – funkid May 18 '19 at 15:21

1 Answers1

1
  1. Dependency injection and variable declaration
import { Renderer2 } from '@angular/core';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';

constructor(
  private renderer: Renderer2,
  private domSanitizer: DomSanitizer
) {}

content: SafeHtml;
private mockMarkdownContent = '<h1 id="test1">Test 1<a href="#test1" title="Permanent link">&para;</a></h1>';
  1. Convert string to DOM (reference)
const template = this.renderer.createElement('template');
template.innerHTML = this.mockMarkdownContent.trim();
  1. Modify anchors (reference)
const anchorNodes: NodeList = template.content.querySelectorAll('a');
const anchors: Node[] = Array.from(anchorNodes);
for (const anchor of anchors) {
  const href: string = 
    (anchor as HTMLAnchorElement).getAttribute('href');
  if (href.indexOf('#') === 0) {
    this.renderer.setProperty(
      anchor,
      'href',
      `/prefix/link/here${href}`
     );
  }
}
  1. Prevent Angular from sanitizing the HTML string (reference)
this.content = 
  this.domSanitizer.bypassSecurityTrustHtml(template.innerHTML);
  1. Bind processed content in HTML template
<div [innerHTML]="content"></div>
funkid
  • 577
  • 1
  • 10
  • 30