Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 5. How to dynamically add links to strings containing a certain tag. like '@'

I have a template view which looks like this

<div class="post-content">
      <p>{{ post.content }}</p>
</div>

where post.content is a type of string.

The string may or may not contain one or more @ tag which references different users. example: '@username'. I want to make this tag clickable with a link. Sort of insert it as an anchor tag:

<a>@username</a>

so far I have tried to string manipulate it manually, and inserting the anchor tag inside the string. However this just shows up as plain text in the view.

How do I go about this in Angular 5?

like image 843
Jonas Praem Avatar asked Jan 25 '18 18:01

Jonas Praem


People also ask

Can we use href in Angular?

AngularJS ng-href DirectiveThe ng-href directive should be used instead of href if you have AngularJS code inside the href value. The ng-href directive makes sure the link is not broken even if the user clicks the link before AngularJS has evaluated the code.

Which element can the users click to jump from one document to another?

In computing, a hyperlink, or simply a link, is a digital reference to data that the user can follow or be guided by clicking or tapping. A hyperlink points to a whole document or to a specific element within a document. Hypertext is text with hyperlinks.


2 Answers

You have to use the innerHTML property to render the provided string as HTML, so instead of

<p> {{post.content}} </p>

You should use

<p [innerHTML]="post.content"></p>

Demo

However, this method is not safe and is prone to XSS if not handled properly,


The recommended method: Create a pipe with DOM Sanitization

linkify.pipe.ts

import { Pipe, PipeTransform } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';

@Pipe({
  name: 'linkify'
})
export class LinkifyPipe implements PipeTransform {

  constructor(private _domSanitizer: DomSanitizer) {}

  transform(value: any, args?: any): any {
    return this._domSanitizer.bypassSecurityTrustHtml(this.stylize(value));
  }

  // Modify this method according to your custom logic
  private stylize(text: string): string {
    let stylizedText: string = '';
    if (text && text.length > 0) {
      for (let t of text.split(" ")) {
        if (t.startsWith("@") && t.length>1)
          stylizedText += `<a href="#${t.substring(1)}">${t}</a> `;
        else
          stylizedText += t + " ";
      }
      return stylizedText;
    }
    else return text;
  }

}

You can modify the stylize method according to your logic.

Usage:

<p [innerHTML]="sample | linkify"></p>

Demo Stackblitz

like image 183
cyberpirate92 Avatar answered Nov 15 '22 02:11

cyberpirate92


cyberpirate92's answer is great, though it has one issue: if a link is at the end of the line, the \n will cause the next word on the next line will get captured as well.

I adapted their answer to work on http links as well:

import { Pipe, PipeTransform } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';

@Pipe({ name: 'linkify' })
export class LinkifyPipe implements PipeTransform {

  constructor(private _domSanitizer: DomSanitizer) {}

  transform(value: any, args?: any): any {
    return this._domSanitizer.bypassSecurityTrustHtml(this.stylize(value));
  }

  // Modify this method according to your custom logic
  private stylize(text: string): string {
    let stylizedText: string = '';
    if (text && text.length > 0) {
      for (let line of text.split("\n")) {
        for (let t of line.split(" ")) {
          if (t.startsWith("http") && t.length>7) {  
            stylizedText += `<a href="${t}">${t}</a> `;
          }
          else
            stylizedText += t + " ";
        }
        stylizedText += '<br>';
      }
      return stylizedText;
    }
    else return text;
  }

}
like image 20
Isaac Abadi Avatar answered Nov 15 '22 02:11

Isaac Abadi