6

I am trying to create a directive that modifies the element's innerHTML by adding links to those substrings which start with @ symbol.

This is what I have tried so far,

linkify.directive.ts

  constructor(private elementRef: ElementRef, private renderer: Renderer2) { 
      let elementText = this.elementRef.nativeElement.innerHTML;
      // elementText = '@user mentioned you';
      console.log(`Element Text: ${elementText}`);
      this.renderer.setProperty(this.elementRef.nativeElement, 'innerHTML', this.stylize(elementText));
  }

and I'm using it like this

<p linkify> Hey @user check this out! </p>

While debugging I have made the following observations,

  • this.elementRef.nativeElement.innerHTML always has an empty string.
  • this.renderer.setProperty(this.elementRef.nativeElement, 'innerHTML', 'something'); is appending something to the beginning of the element's text instead of replacing.

Question 1: How to access the innerHTML of an element?

Question 2: How to set the innerHTML of an element from a directive?

Stackblitz demonstrating the problem

I tried the documentation for Renderer2, but it's of no help for me.

1
  • 1
    make it a pipe instead and use the dom sanitizer Commented Jan 25, 2018 at 20:23

1 Answer 1

5

As @bryan60 suggested, The ideal way to do this is to create a pipe instead of a directive.

This is the pipe I ended up creating,

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));
  }

  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;
  }

}

Usage:

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

Demo Stackblitz

Sign up to request clarification or add additional context in comments.

2 Comments

glad it worked out. I'm surprised you need to access the inner HTML directly though using the dom sanitizer. i thought <p>{{ text | linkify }}</p> would just work like normal. I had to do soemthing very close to this and that's the syntax I got working eventually. Don't remember how though.
@bryan60 I initially tried using just that, but was getting this issue, turns out strings sanitized using the DomSanitizer should be bound to innerHTML, else they'll end up rendering the sanitized markup as plain text.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.