Highlight matching text filter javascript


I'm doing a search filter highlight. But it renders [object Object] instead of <mark>match values</mark> when replacing the values.

Currently I have this code.

this.countries.response.filter((val) => {
  const position = val.value.toLowerCase().indexOf(this.controls.country.toLowerCase());
  if (this.controls.country == "") {
    return val;
  } else if (position !== -1) {
    return val;
  }
}).map((e) => {
    const position = e.value.toLowerCase().indexOf(this.controls.country.toLowerCase());
    let matches = e.value.substring(position, this.controls.country.length + position);
    const regex = new RegExp(matches, 'gi');
    const highlighted = e.value.replace(regex, '<mark>'+{matches}+'</mark>');
      return (
        <li class="lov-val list-group-item">
          <p>{highlighted}</p>
        </li>
    )
})

And I am having this output.

I'm doing something like this.

---------------Answer---------------

Without knowing all your code, I suspect you are only missing one step. You get an HTMLCollection. You have to iterate this and enclose the match - as you already did correctly - with mark.

Here is an example that makes it even clearer for you.

const term = "c"
const countries = document.querySelectorAll("#countries div");    

for(let i = 0; i < countries.length; i++) {  
  countries[i].innerHTML = countries[i].innerHTML.replace(new RegExp(term, "gi"), (match) => `<mark>${match}</mark>`);  
}
<div id="countries">
  <div class="item">USA</div>
  <div class="item">China</div>
  <div class="item">Canada</div>
</div>
<div id="output"></div>
---------------Answer---------------

You're seeing [object Object] because you're appending an object to your string with {matches}. You should do something like '<mark>' + matches + '</mark>' so that you append a string instead.

However that probably won't fix the issue. I suspect you'll still see the string '<mark>EXAMPLE_TEXT</mark>' in your output instead of actual html. This is because text content containing valid html is just interpreted as text, the browser won't parse it as html.

It looks like you're writing jsx, so I'm assuming you're using React. An easy fix would be to use the dangerouslySetInnerHTML prop. However there are security concerns with using this (hence the cautious name) so use it at your own discretion.

I don't have an immediate alternative at mind, but I imagine there should be some way to break up each country string into separate components without having to use dangerouslySetInnerHTML and regex replace shenanigans.

e.g.

<span>
  <span>
    SOUTH
  </span>
  <mark>
    AME // this is the part that's highlighted
  </mark>
  <span>
    RICA
  </span>
</span>

Previous : Conversion of Future<List> to List in Flutter
Next : this current code needs pagination and sort, how i do?