I had this project where search results coming from a API service needed to be highlighted.

This was my template, containing a long string (a search snippet):

<div [innerHTML]="child.contents"></div>

Solution

I figured out the best way to do this was to use a Pipe. This is good practice to transform output in your Angular template.

Creating an angular pipe

In my app/pipes/ folder I created highlight.pipe.ts

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

@Pipe({
  name: 'highlight'
})
export class HighlightPipe implements PipeTransform {
  constructor(private sanitizer: DomSanitizer) {}

  transform = (text: string, search: string): SafeHtml => {
    if (search && text) {
      let pattern = search.replace(
        /[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,
        '\\$&'
      );
      pattern = pattern
        .split(' ')
        .filter((t: string) => t)
        .join('|');

      const regex = new RegExp(pattern, 'gi');
      return this.sanitizer.bypassSecurityTrustHtml(
        text.replace(
          regex,
          match => `<span style="background:yellow;">${match}</span>`
        )
      );
    } else {
      return text;
    }
  }
}

Updating the template

Make sure you declare or import the pipe in your module:

  declarations: [
    HighlightPipe
  ],
  exports: [
    HighlightPipe
  ],
  providers: [
    HighlightPipe
  ],

Now in your mypage.page.ts:

<div [innerHTML]="child.contents | highlight:search.value"></div>

Done!

Credits

This code was based on an example on this example, which I updated it to work properly with Strict TypeScript and Angular 13.

 

 

Saved you some valuable time?

Buy me a drink 🍺