Skip to content

Instantly share code, notes, and snippets.

@rifayetuxbd
Last active June 10, 2022 05:39
Show Gist options
  • Select an option

  • Save rifayetuxbd/5aa5719aaf8d2e1b1b43c66f0c1c42ab to your computer and use it in GitHub Desktop.

Select an option

Save rifayetuxbd/5aa5719aaf8d2e1b1b43c66f0c1c42ab to your computer and use it in GitHub Desktop.

Create a highlighter using Angular directive

highlight.directive.ts

import {
  Directive,
  HostBinding,
  Input,
  OnChanges,
  SecurityContext,
  SimpleChanges
} from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
import { escapeRegExpSpecialChars } from '../../functions/escape-regular-expression-special-chars.function';

@Directive({
  selector: '[highlight]'
})
export class HighlightDirective implements OnChanges {

  /**
   * Text to search with
   */
  @Input('highlight') searchTerm: string | null = null;

  /**
   * The full text from which the search will apply
   */
  @Input() fullText: string | null = null;

  /**
   * Is case sensitive or not. Pass __true__ for case sensitive search.
   * 
   * Default is false
   */
  @Input() caseSensitive: boolean = false;

  /**
   * Any additional custom class for the highlited text.
   * 
   * Default is '';
   */
  @Input() customClasses: string = '';

  /**
   * The property that is going to binded after the search
   */
  @HostBinding('innerHTML')
  private content: string | null = null;


  constructor(
    // private readonly _element: ElementRef,
    private readonly _sanitizer: DomSanitizer
  ) { }

  ngOnChanges(changes: SimpleChanges): void {
    this.content = this.fullText;

    if (!this.fullText) {
      // console.log(
      //   "%cPlease give full text to highlight text",
      //   "color: red; font-size: 16px",
      //   "\nExample: <span [highlight]='he' [fullText]='text'>{{ text }}</span>\nIt will highlight he from {{text}}"
      // );
      return;
    }

    // To convert any type of data to string
    // User may pass number, date or any other type of data
    this.fullText = this.fullText + '';

    const searchTerm = changes["searchTerm"];

    if (!searchTerm) {
      return;
    }

    // get current value of the search term
    const currentSearchTerm = searchTerm["currentValue"];

    if (!currentSearchTerm) {
      return;
    }

    // g: case sensitive
    // gi: case insensitive
    const regex = new RegExp(escapeRegExpSpecialChars(currentSearchTerm), this.caseSensitive ? 'g' : 'gi');

    const highlitedText = this.fullText.replace(regex, (match: string) => {
      return `<mark class="${this.customClasses}">${match}</mark>`;
    });

    // Sanitize the text to avoid xss attack
    const sanitizedText = this._sanitizer.sanitize(
      SecurityContext.HTML,
      highlitedText
    );

    // insert the text to the innerhtml
    this.content = sanitizedText ?? this.content;
  }
}

Usage in html file

<input matInput (keyup)="applySearchFilter($event)" type="text" #searchInLogConsole>

<table class="table" mat-table [dataSource]="dataSource" matSort>
........
........
  
  <!-- SYSNO Column -->
  <ng-container matColumnDef="SYSNO" *ngIf="displayedColumns.includes('SYSNO')">
    <th mat-header-cell *matHeaderCellDef mat-sort-header> SYSNO </th>
    <td mat-cell *matCellDef="let pc" [highlight]="searchInLogConsole.value" [fullText]="pc.SYSNO">
      {{ pc.SYSNO }}
    </td>
  </ng-container>
 
........
........
</table>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment