Search code examples
angularangular-routerangular-routerlinkangular-dom-sanitizer

Best way to pass angular routerLink URL's in an HTML string


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?


Solution

  • 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>