Highlight the search text - angular 2

前端 未结 7 810
心在旅途
心在旅途 2020-12-01 05:22

A messenger displays the search results based on the input given by the user. Need to highlight the word that is been searched, while displaying the result. These are the h

相关标签:
7条回答
  • 2020-12-01 05:38

    If you have multiple words in your string than use pipe which accepts array and highlight each word in result.

    You can use following pipe for multiple search words:-

    import { Pipe, PipeTransform } from '@angular/core';
    
    @Pipe({
        name: 'highlight'
    })
    
    export class HighlightText implements PipeTransform {
    
        transform(value: any, args: any): any {
            if (!args) {return value;}
            for(const text of args) {
                var reText = new RegExp(text, 'gi');
                value = value.replace(reText, "<mark>" + text + "</mark>");
                //for your custom css
                // value = value.replace(reText, "<span class='highlight-search-text'>" + text + "</span>"); 
    
    
            }
            return value;
        }
    }
    

    Split you string to generate array of strings.

    var searchTerms = searchKey.split(' ');
    

    usage:

    <div [innerHTML]="result | highlight:searchTerms"></div>
    

    If you wanted to use custom class :

    .highlight-search-text {
      color: black;
      font-weight: 600;
    }
    

    All the best!

    0 讨论(0)
  • 2020-12-01 05:39

    Building on a previous answer (HighlightedText-Component) I ended up with this:

    import { Component, Input, OnChanges } from "@angular/core";
    
    @Component({
        selector: 'highlighted-text',
        template: `
            <ng-container *ngFor="let match of result">
                <mark *ngIf="(match === needle); else nomatch">{{match}}</mark>
                <ng-template #nomatch>{{match}}</ng-template>
            </ng-container>
        `,
    })
    export class HighlightedTextComponent implements OnChanges {
        @Input() needle: string;
        @Input() haystack: string;
        public result: string[];
    
        ngOnChanges() {
            const regEx = new RegExp('(' + this.needle + ')', 'i');
            this.result = this.haystack.split(regEx);
        }
    }
    

    This way also multiple matches of the needle are highlighted. The usage of this component is similar to the one in the previous answer:

    <highlighted-text [needle]="searchInput" [haystack]="value"></highlighted-text>
    

    For me this approach using a component feels more secure, since I do not have to use "innerHtml".

    0 讨论(0)
  • 2020-12-01 05:41

    One difficulty the innerHTML method has is in styling the <mark> tag. Another method is to place this in a component, allowing for much more options in styling.

    highlighted-text.component.html

    <mark *ngIf="matched">{{matched}}</mark>{{unmatched}}
    

    highlighted-text.component.ts

    import { Component, Input, OnChanges, OnInit } from "@angular/core";
    
    @Component({
        selector: "highlighted-text",
        templateUrl: "./highlighted-text.component.html",
        styleUrls: ["./highlighted-text.component.css"]
    })
    export class HighlightedTextComponent implements OnChanges {
        @Input() needle: String;
        @Input() haystack: String;
        public matched;
        public unmatched;
    
        ngOnChanges(changes) {
            this.match();
        }
    
        match() {
            this.matched = undefined;
            this.unmatched = this.haystack;
            if (this.needle && this.haystack) {
                const needle = String(this.needle);
                const haystack = String(this.haystack);
                const startIndex = haystack.toLowerCase().indexOf(needle.toLowerCase());
                if (startIndex !== -1) {
                    const endLength = needle.length;
                    this.matched = haystack.substr(startIndex, endLength);
                    this.unmatched = haystack.substr(needle.length);
                }
            }
        }
    }
    

    highlighted-text.component.css

    mark {
        display: inline;
        margin: 0;
        padding: 0;       
        font-weight: 600;
    }
    

    Usage

    <highlighted-text [needle]=searchInput [haystack]=value></highlighted-text>
    
    0 讨论(0)
  • 2020-12-01 05:50

    You can do that by creating a pipe and applying that pipe to the summary part of array inside ngfor. Here is the code for Pipe:

    import { Pipe, PipeTransform } from '@angular/core';
    
    @Pipe({
        name: 'highlight'
    })
    
    export class HighlightSearch implements PipeTransform {
    
        transform(value: any, args: any): any {
            if (!args) {return value;}
            var re = new RegExp(args, 'gi'); //'gi' for case insensitive and can use 'g' if you want the search to be case sensitive.
            return value.replace(re, "<mark>$&</mark>");
        }
    }
    

    and then in markup apply it on a string like this:

    <div innerHTML="{{ str | highlight : 'search'}}"></div>
    

    Replace 'search' with the word you want to highlight.

    Hope this will help.

    0 讨论(0)
  • 2020-12-01 05:55

    To expand on Kamal's answer,

    The value coming into the transform method, could be a number, perhaps a cast to string String(value) would be safe thing to do.

    transform(value: string, args: string): any {
        if (args && value) {
            value = String(value); // make sure its a string
            let startIndex = value.toLowerCase().indexOf(args.toLowerCase());
            if (startIndex != -1) {
                let endLength = args.length;
                let matchingString = value.substr(startIndex, endLength);
                return value.replace(matchingString, "<mark>" + matchingString + "</mark>");
            }
    
        }
        return value;
    }
    
    0 讨论(0)
  • 2020-12-01 06:03

    The selected answer has the following issues:

    1. It will return undefined if there is nothing provided in the search string
    2. The search should be case insensitive but that should not replace the original string case.

    i would suggest the following code instead

    transform(value: string, args: string): any {
        if (args && value) {
            let startIndex = value.toLowerCase().indexOf(args.toLowerCase());
            if (startIndex != -1) {
                let endLength = args.length;
                let matchingString = value.substr(startIndex, endLength);
                return value.replace(matchingString, "<mark>" + matchingString + "</mark>");
            }
    
        }
        return value;
    }
    
    0 讨论(0)
提交回复
热议问题