1

I have a notification service in my angular app, typically you call it like

this.notificationsService.showError('My Title', 'My Message...');

I'd like to have the ability to to pass app links in the messages as well, and I know I need to allow SafeHtml input, like this:

this.notificationsService.showError(
  'Error!',
  this.domSanitizer.bypassSecurityTrustHtml(
    `Something has gone wrong, but you can go to <a routerLink="'/home/accounts-list'">home page</a> to start over.`
  )
);

Over in my service, this is what I do with it:

showError(title: string, message: string | SafeHtml): void {
    const newNotification: INotification = {
        title,
        message,
        htmlMessage: typeof message !== 'string'
    };

    this.notifications.push(newNotification);
}

And then I show it like this:

<div class="toast" *ngFor="let n of notificationsService.notificationsList">
    <div class="toast-header">
        <strong>{{n.title}}</strong>
    </div>
    <div class="toast-body" *ngIf="!n.htmlMessage">{{n.message}}</div>
    <div class="toast-body" *ngIf="n.htmlMessage" [innerHTML]="n.message"></div>
</div>

So... to get to the point of this question! This only somewhat works in that the HTML gets though, but apparently it's not being parsed by angular to make the routerLink functional. The actual HTML output to the browser is:

<a routerlink="'/home/accounts-list'">home page</a>

however, it's not clickable since a link that's actually parsed by angular would output this HTML:

<a routerlink="'/home/accounts-list'" ng-reflect-router-link="/home/accounts-list" href="/home/accounts-list">home page</a>

How can I get these links to work?

Am I even going about this in the correct way?

Chris Barr
  • 29,851
  • 23
  • 95
  • 135
  • 1
    Your toast dialog needs to use `TemplateRef` instead of HTML as strings, and then you pass a reference to a `` which contains the dynamic Angular content that you need. – Reactgular Apr 26 '19 at 19:26
  • so i have to make a template in my HTML that's only being used to pass to a service? Is there no way to compile a string? – Chris Barr Apr 26 '19 at 19:53

2 Answers2

1

This is what I ended up doing based on @cgTag's comment & suggestion

on my page that shows the error I have this:

<ng-template #errorMessageTemplate>
    Something has gone wrong, but you can go to the <a [routerLink]="['/home/accounts-list']">home page</a>
</ng-template>
@ViewChild('errorMessageTemplate') errorMessageTemplate!: TemplateRef<NgTemplateOutlet>;


someMethod(): void {
  this.notificationsService.showError('Error!', this.errorMessageTemplate);
}

And in my service I have this:

showError(title: string, message: string | TemplateRef<NgTemplateOutlet>): void {
    const newNotification: INotification = {
        title,
        message,
        messageAsTemplate: typeof message !== 'string'
    };

    this.notifications.push(newNotification);
}

And then I show it like this:

<div class="toast" *ngFor="let n of notificationsService.notificationsList">
    <div class="toast-header">
        <strong>{{n.title}}</strong>
    </div>
    <div class="toast-body" *ngIf="!n.messageAsTemplate">{{n.message}}</div>
    <div class="toast-body" *ngIf="n.messageAsTemplate">
        <ng-container [ngTemplateOutlet]="n.message"></ng-container>
    </div>
</div>
Chris Barr
  • 29,851
  • 23
  • 95
  • 135
0

Since the HTML is not compiled by the angular compiler, there is no good solution. :)

There are some hacks to achieve what you want. But they are dirty and possibly insecure.

One solution is to create a directive which sits on the host element. It watches clicks on the host and prevents the default action if the clicked element has the routerlink attribute. it then just calls the router.navigate function with the value of routerlink attribute.

I prepared a quick example on stackblitz: https://stackblitz.com/edit/angular-ttfwwg

A.Winnen
  • 1,680
  • 1
  • 7
  • 13
  • Wow, yeah i don't love that idea - but good to know, thanks. I'm not actually too surprised that this isn't in Angular since it would be a bit of a security risk. – Chris Barr Apr 26 '19 at 19:58