Can't Render Routerlink In Innerhtml In Angular
Solution 1:
As you've discovered, you can't have a dynamic template in Angular because the templates are bundled with components as javascript. If you want to learn more, check out this issue on github. The upshot of it is: dynamic templates would break AOT compilation.
You have also discovered that you can set the innerHTML
of an object to arbitrary HTML, but routerLink
won't work in that context. Why? Because routerlink
is an Angular directive, not an HTML attribute. Since we are just setting the innerHTML
, it's not a compiled template.
So, what's the solution? Let's back up and think about what routerLink
is doing in the first place. As it turns out, not much. Take a look at the source. Specifically, this is what it's doing when an element with the routerLink
directive is clicked:
@HostListener('click')
onClick(): boolean {
const extras = {
skipLocationChange: attrBoolValue(this.skipLocationChange),
replaceUrl: attrBoolValue(this.replaceUrl),
};
this.router.navigateByUrl(this.urlTree, extras);
returntrue;
}
It's just using HostListener
to monitor clicks, and routing accordingly. We can do something similar in our component. I've called it FooterComponent
since you mentioned that this was a footer with dynamic HTML:
import { Component, Input, HostListener } from'@angular/core';
import { Router } from'@angular/router';
@Component({
selector: 'app-footer',
template: '<div [innerHTML]="footerHtml"></div>'
})
exportclassFooterComponent {
@Input() footerHtml: string = "";
constructor(private router: Router) { }
// Watch for clicks in our component
@HostListener("click", ['$event'])
onClick(event: MouseEvent) {
// If we don't have an anchor tag, we don't need to do anything.if (event.targetinstanceofHTMLAnchorElement === false) {
return;
}
// Prevent page from reloading
event.preventDefault();
let target = <HTMLAnchorElement>event.target;
// Navigate to the path in the linkthis.router.navigate([target.pathname]);
}
}
As you can see, it takes in input called footerHtml
, which is of type string. To use it, we will add this somewhere:
<app-footer [footerHtml]="footerHtml"></app-footer>
Where the footerHtml
property in our component is defined as follows:
footerHtml = '<p>This is the footer with a <a href="/admin">link!</a></p>';
When the element is clicked, we check to make sure the user clicked on a hyperlink. If they did, we navigate using the router and prevent the default behavior. Here's a working StackBlitz example. Hope this helps!
Solution 2:
Based on the question, #Dean solution works fine however, it does not work for external link. That is, it can only work for angular route path. Below is my solution to solve both internal and external url/link.
import { Component, Input, HostListener } from'@angular/core';
import { Router } from'@angular/router';
import { Component, Input, HostListener } from'@angular/core';
import { Router } from'@angular/router';
@Component({
selector: 'app-footer',
template: '<div [innerHTML]="footerHtml"></div>'
})
exportclassFooterComponent {
footerHtml = '<p>This is the innerHTML content with angular valid path <a href="/admin">internal link!</a> and external link <a target="_blank" href="https://google.com">external link</a></p>';
// Watch for clicks in our component@HostListener('click', ['$event'])
onClick(event: MouseEvent) {
this.routingService.urlLocator(event);
// Do nothing if no anchor tag.if (event.targetinstanceofHTMLAnchorElement === false) {
return;
}
// Prevent normal html anchor behaviour
event.preventDefault();
// Checks if the anchor has a full url name or if target is "_blank"// That is, target external urlif (event.target.target === '_blank') {
// open it in new window (You can decide to use window.location.href)window.open(event.target.href);
} else {
// handle valid angular route pathconst target = <HTMLAnchorElement>event.target;
this.router.navigate([target.pathname]);
}
}
}
Solution 3:
If you don't mind installing a library for this, have a look at ngx-dynamic-hooks. It can replace any piece of text in a dynamic string of content with an actual Angular component - including link-elements.
Funnily enough, I've written an example based on the exact idea of automatically replacing internal links with [RouterLinks]
. Have a look at it here (or in this Stackblitz).
Post a Comment for "Can't Render Routerlink In Innerhtml In Angular"