-1

Below is my code I used to Highlight Search values in my list. I used a function getHighlightedText and passed this function to my list.

getHighlightedText = text => {
  // search value stored in this.state.value
  const { value } = this.props;
  const space = new RegExp('\\b\\B\\W+\\B\\b]', 'g');
  // value is split
  const findWords = value.split(space).map(fw => fw.toLowerCase());
  console.log('split the value:', findWords)
  // text is split
  const textWords = text.split(space);
  console.log('split the search:', textWords)

  // each word in the array is mapped
  const output = textWords.map(word => {
    const lower = word.toLowerCase();
    // logic to check search value includes word
    if (findWords.includes(lower)) {
      return <Text style = {{backgroundColor: 'coral'}}>{word}</Text>
    } else {
      return <Text>{word}</Text>
    }
  });
  return <Text>{output}</Text> 
}

// using my getHighlightedText in my renderItem
return <Text>{getHighlightedText(Desc)}</Text>;

This logic works fine only for complete strings and not for partial strings. In the below image, "json" and "url" are highlighted correctly. But as I typed "Noti" and not "Notification" this string is not highlighted.

How can I achieve this?? any ideas pleaseeee

grooot
  • 446
  • 2
  • 10
  • 31
  • Hi, it looks more improve then previous question! This problems is that includes is not work like you think, last time I use includes is [string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/includes), but this time your is an [array](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Array/includes). Array includes is compare with element like `if(a==b[0])` – 高鵬翔 May 04 '20 at 05:55
  • So the problem is [How to check partial string in array of strings](https://stackoverflow.com/questions/4556099/in-javascript-how-do-you-search-an-array-for-a-substring-match) Hope this could help.Something in condition like `findWords.findIndex(element => element.includes("substring"))` if it `> -1` (Didn't find return -1) – 高鵬翔 May 04 '20 at 07:46
  • Hi, yes I have changed the code several times and sadly none of it works correctly :D I tried the findIndex way but it didn't work. Ex: myArray [dog, cat, car] now if my condition is like myArray.findIndex(element => element.includes("Catalina")). This won't work. – grooot May 04 '20 at 08:28
  • I have try this `myArray.findIndex(element => element.includes("ca"))` could return correct. and return -1 when not found. So you could condition like I've said set like if it return `> -1` is having this word. It could be `if(myArray.findIndex(element => element.includes("ca")) > -1){return...}else{return...}` – 高鵬翔 May 04 '20 at 08:50
  • No No so confusing I know :D :D in my code I have stored my search value in myArray. so if my search value is "cat dog" then my array will have ["cat", "dog"]. Now I am Checking my list with this Array and not the other way round. – grooot May 04 '20 at 08:55
  • But isn't this condition in map? So the word should be only one word to let you find if it is include in your maybe not myArray use `findWords`? Like `if(findWords.findIndex(element => element.includes(lower)) > -1)){...}else{...}` – 高鵬翔 May 04 '20 at 09:05
  • yes the condition is in map and it takes only one word. if that word is "notification" and our search value is "notif" don't you think the return index will be -1 ?? – grooot May 04 '20 at 09:18
  • Isn't findWords is split from original word like "notification"? and lower comes form user type like "notif" ? If yes, find index in array have notification and notification have "notif" will return >-1 like 0,1,2,3..? – 高鵬翔 May 04 '20 at 09:24
  • I've try like [this](https://js.do/code/dogtest) , is it similar? – 高鵬翔 May 04 '20 at 09:28
  • no no that was my old code and it did not work for multiple search value. Ex: search value "cat dog" it used to only search for cat not dog. In this thread I have given my updated code and now multiple search works. But partial search doesn't work. – grooot May 04 '20 at 09:37
  • The example is based on one round of map, not only one of search value, dog will search at next round of map? – 高鵬翔 May 04 '20 at 09:41
  • no just one round of map. in that one round of map for each word the code checks whether this word exists in our search value array. – grooot May 04 '20 at 09:44
  • I'm not sure if I realize, but if it's just contrary, it could be `if(findWords.findIndex(element => lower.includes(element )) > -1)){...}else{...}` ? – 高鵬翔 May 04 '20 at 09:51

1 Answers1

0

changed my highlight function and it works.

<Text numberOfLines={3} 
  style = {
    [subTitle, {
      fontSize: normalizeFontSize(14),
      lineHeight: normalizeLineHeight(14)
    }]
  }>
  {getHighlightedText(alert)}
</Text>

highlight function:

getHighlightedText = text => {
  // search text user inputs
  const {value} = this.props;

  if (value == "" || value == null || value == 0) {
    return <Text>{text}</Text>
  } else {
    // split the search value
    const words = value.split(/\s+/g).filter(word => word.length);
    // join if search value has more than 1 word
    const pattern = words.join('|');

    const re = new RegExp(pattern, 'gi')
    const children = [];

    let before, highlighted, match, pos = 0;
    // match using RegExp with my text
    const matches = text.match(re);

    if (matches != null) {
      // loop all the matches
      for (match of matches) {
        match = re.exec(text)

        if (pos < match.index) {
          // before has all the text before the word
          // that has to highlighted
          before = text.substring(pos, match.index);

          if (before.length) {
            children.push(before)
          }
        }
        highlighted = <Text style=
            {{backgroundColor: 'coral'}}>{match[0]}</Text>
        // text is highlighted
        children.push(highlighted);

        pos = match.index + match[0].length;
      }
    }
    if (pos < text.length) {
      // text after the highlighted part
      const last = text.substring(pos);
      children.push(last);
    }
    // children array will have the entire text
    return <Text>{children}</Text>
  }
}
grooot
  • 446
  • 2
  • 10
  • 31