简体   繁体   English

突出显示搜索文本 - angular 2

[英]Highlight the search text - angular 2

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 html and component that is been used.这些是使用的 html 和组件。

Component.html组件.html

 <div *ngFor = "let result of resultArray">
<div>Id : result.id </div>
<div>Summary : result.summary </div>
<div> Link : result.link </div>
</div>

Component.ts组件.ts

resultArray : any = [{"id":"1","summary":"These are the results for the searched text","link":"http://www.example.com"}]

This resultArray is fetched from hitting the backend service by sending the search text as input.这个 resultArray 是通过发送搜索文本作为输入来访问后端服务的。 Based on the search text, the result is fetched.根据搜索文本,获取结果。 Need to highlight the searched text, similar to google search.需要高亮搜索到的文字,类似google搜索。 Please find the screenshot,请找到截图,

在此处输入图片说明

If I search for the word "member", the occurence of the word "member" gets highlighted.如果我搜索“成员”这个词,“成员”这个词的出现就会突出显示。 How to achieve the same using angular 2. Please suggest an idea on this.如何使用 angular 2 实现相同的效果。请对此提出建议。

You can do that by creating a pipe and applying that pipe to the summary part of array inside ngfor .您可以通过创建一个管道并将该管道应用到ngfor中数组的摘要部分来做到这ngfor Here is the code for Pipe :这是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.希望这会有所帮助。

The selected answer has the following issues:所选答案存在以下问题:

  1. It will return undefined if there is nothing provided in the search string如果搜索字符串中没有提供任何内容,它将返回 undefined
  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;
}

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!一切顺利!

One difficulty the innerHTML method has is in styling the <mark> tag. innerHTML 方法的一个难点在于<mark>标签的样式。 Another method is to place this in a component, allowing for much more options in styling.另一种方法是将其放置在组件中,从而在样式中提供更多选项。

highlighted-text.component.html突出显示的text.component.html

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

highlighted-text.component.ts突出显示的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突出显示的text.component.css

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

Usage用法

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

Building on a previous answer (HighlightedText-Component) I ended up with this:基于以前的答案(HighlightedText-Component),我最终得到了这个:

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".对我来说,这种使用组件的方法感觉更安全,因为我不必使用“innerHtml”。

To expand on Kamal's answer,为了扩展 Kamal 的答案,

The value coming into the transform method, could be a number, perhaps a cast to string String(value) would be safe thing to do.进入转换方法的值可以是一个数字,也许转换为字符串String(value)是安全的做法。

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

I would suggest to escape the search String like this我建议像这样转义搜索字符串

 RegExp.escape = function(string) {
  if(string !== null){ return string.toString().replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
  } else return null
};

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

  transform(value: any, args: any): any {
    if (!args || value == null) {
      return value;
    }
    // Match in a case insensitive maneer
    const re = new RegExp(RegExp.escape(args), 'gi');

      const  match = value.match(re);



    // If there's no match, just return the original value.
    if (!match) {
      return value;
    }

    const replacedValue = value.replace(re, "<mark>" + match[0] + "</mark>")
    return this.sanitizer.bypassSecurityTrustHtml(replacedValue)
  }
}

Variant off of the accepted answer that worked for my purposes. 改变了对我有用的公认答案。

 transform(value: any, args: any): any {
  const args1 = args.toLowerCase()
  const args2 = this.capitalizeFirstLetter(args)
  if(args === args1 || args === args2){
    if (!args) {return value;}
    var re1 = new RegExp(args1, 'g'); //'gi' for case insensitive and can use 'g' if you want the search to be case sensitive.
    var re2 = new RegExp(args2, 'g'); //'gi' for case insensitive and can use 'g' if you want the search to be case sensitive.
    let info = value.replace(re1, "<mark>" + args1 + "</mark>");
    return info.replace(re2, "<mark>" + args2 + "</mark>");
  }
  else{
    args = args.toLowerCase()
    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>" + args + "</mark>");
  }

} }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM