Search code examples
jqueryhtmlautocompletehighlight

Search and highlight text on page while keeping html structure


Similar questions might have been asked already, but please read the details carefully.

I am using kind of a self-made autocomplete, and now I want to highlight the search term inside the result set. This works so far, but only on plain text. The problem is: I need to keep the html structure, if there is one in the result div. Please see my sample: currently I am loosing the included span's with the class bold. How can I keep them?

Thank you for any advice!

$('#box').keyup(function () {
  const valThis = this.value;
  const length  = this.value.length;

  $('.objType').each(function () {
    const text  = $(this).text();
    const textL = text.toLowerCase();
    const position = textL.indexOf(valThis.toLowerCase());

    if (position !== -1) {
      const matches = text.substring(position, (valThis.length + position));
      const regex = new RegExp(matches, 'ig');
      const highlighted = text.replace(regex, `<mark>${matches}</mark>`);

      $(this).html(highlighted).show();
    } else {
    	$(this).text(text);
      $(this).hide();
    }
  });

});
input[type="text"] { 
    width: 50%;
    margin:10px;
    padding: 5px;
    float:left;
    clear:left;
}
div{
  float:left;
  clear:left;
  margin:10px 10px;
}
.bold {
  font-weight: 700;
}
table td {
  border: solid 1px #ccc;
  padding: 3px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.0/jquery.min.js"></script>
<input placeholder="Filter results" id="box" type="text" />

<div class="objType" id="item1">
  <span class="bold">Accepted</span> Event Relation
  <table>
  <tr>
    <td>Lorem</td>
    <td>ipsum</td>
  </tr>
  </table>
</div>
<div class="objType" id="item2">
  Case <span class="bold">Status</span> Value
  <table>
  <tr>
    <td>Lorem</td>
    <td>ipsum</td>
  </tr>
  </table>
</div>
<div class="objType" id="item3">
  External <span class="bold">Data Source</span>
  <table>
  <tr>
    <td>Lorem</td>
    <td>ipsum</td>
  </tr>
  </table>
</div>
<div class="objType" id="item4">
  Navigation <span class="bold">Link</span> Set
  <table>
  <tr>
    <td>Lorem</td>
    <td>ipsum</td>
  </tr>
  </table>
</div>

PS: a JSFiddle for this in addition might be helpful => https://jsfiddle.net/SchweizerSchoggi/6x3ak5d0/7/


Solution

  • Here is a possible base using only native javascript. This behave somewhat like CTRL+F.

    This seems to preserve the <td> elements.

    The clear function replace the mark elements by a wbr element:

    On UTF-8 encoded pages, <wbr> behaves like the U+200B ZERO-WIDTH SPACE code point. https://developer.mozilla.org/en-US/docs/Web/HTML/Element/wbr

    function mark(it){
      clearIt()
      if (it.length > 2){
        let c = new RegExp(it, "ig") 
        main.innerHTML = main.innerHTML.replace(c,"<mark>"+it+"</mark>")
      }  
    }
    
    function clearIt(){
      let b = new RegExp("mark>", "ig") 
      main.innerHTML = main.innerHTML.replace(b,"wbr>")
    }
    
    mark(search.value)
    input[type="text"] { 
        width: 50%;
        margin:10px;
        padding: 5px;
        float:left;
        clear:left;
    }
    div{
      float:left;
      clear:left;
      margin:10px 10px;
    }
    .bold {
      font-weight: 700;
    }
    table td {
      border: solid 1px #ccc;
      padding: 3px;
    }
    <input onfocusout="clearIt()" oninput="mark(this.value)"  value="Lorem" id="search" placeholder="Lorem">
    <button onclick="mark(search.value)">SEARCH</button>
    <button onclick="clearIt()">CLEAR</button>
    
    <div id="main">
    <div class="objType" id="item1">
      <span class="bold">Accepted</span> Event Relation
      <table>
      <tr>
        <td>Lorem</td>
        <td>ipsum</td>
      </tr>
      </table>
    </div>
    <div class="objType" id="item2">
      Case <span class="bold">Status</span> Value
      <table>
      <tr>
        <td>Lorem</td>
        <td>ipsum</td>
      </tr>
      </table>
    </div>
    <div class="objType" id="item3">
      External <span class="bold">Data Source</span>
      <table>
      <tr>
        <td>Lorem</td>
        <td>ipsum</td>
      </tr>
      </table>
    </div>
    <div class="objType" id="item4">
      Navigation <span class="bold">Link</span> Set
      <table>
      <tr>
        <td>Lorem</td>
        <td>ipsum</td>
      </tr>
      </table>
    </div>
    
    </div>

    By the way the restored/cleared markup isn't the original, to fully restore it, you might need to copy the whole html before marking it up.