0

I have a table and a search bar that can search contents from the table. It's working perfectly and only shows the rows that matches the text inputted.

What I want to add is, to highlight the text inputted.

I followed the codes specified here: https://www.w3schools.com/howto/howto_js_filter_table.asp

It's working but I wanted to highlight the texts found.

Like This Sample: http://prntscr.com/pc20vp

I don't want to change too much in my code. I hope there's something I can add.

function myFunction() {
  // Declare variables
  var input, filter, table, tr, td, i, txtValue;
  input = document.getElementById("myInput");
  filter = input.value.toUpperCase();
  table = document.getElementById("myTable");
  tr = table.getElementsByTagName("tr");

  // Loop through all table rows, and hide those who don't match the search query
  for (i = 0; i < tr.length; i++) {
    td = tr[i].getElementsByTagName("td")[0];
    if (td) {
      txtValue = td.textContent || td.innerText;
      if (txtValue.toUpperCase().indexOf(filter) > -1) {
        tr[i].style.display = "";
      } else {
        tr[i].style.display = "none";
      }
    }
  }
}
#myInput {
  background-image: url('/css/searchicon.png');
  /* Add a search icon to input */
  background-position: 10px 12px;
  /* Position the search icon */
  background-repeat: no-repeat;
  /* Do not repeat the icon image */
  width: 100%;
  /* Full-width */
  font-size: 16px;
  /* Increase font-size */
  padding: 12px 20px 12px 40px;
  /* Add some padding */
  border: 1px solid #ddd;
  /* Add a grey border */
  margin-bottom: 12px;
  /* Add some space below the input */
}

#myTable {
  border-collapse: collapse;
  /* Collapse borders */
  width: 100%;
  /* Full-width */
  border: 1px solid #ddd;
  /* Add a grey border */
  font-size: 18px;
  /* Increase font-size */
}

#myTable th,
#myTable td {
  text-align: left;
  /* Left-align text */
  padding: 12px;
  /* Add padding */
}

#myTable tr {
  /* Add a bottom border to all table rows */
  border-bottom: 1px solid #ddd;
}

#myTable tr.header,
#myTable tr:hover {
  /* Add a grey background color to the table header and on hover */
  background-color: #f1f1f1;
}
<input type="text" id="myInput" onkeyup="myFunction()" placeholder="Search for names..">

<table id="myTable">
  <tr class="header">
    <th style="width:60%;">Name</th>
    <th style="width:40%;">Country</th>
  </tr>
  <tr>
    <td>Alfreds Futterkiste</td>
    <td>Germany</td>
  </tr>
  <tr>
    <td>Berglunds snabbkop</td>
    <td>Sweden</td>
  </tr>
  <tr>
    <td>Island Trading</td>
    <td>UK</td>
  </tr>
  <tr>
    <td>Koniglich Essen</td>
    <td>Germany</td>
  </tr>
</table>
mplungjan
  • 169,008
  • 28
  • 173
  • 236
  • Your screen shot disappeared. You can paste one into the question instead, then it will save it to imgur – mplungjan Apr 12 '23 at 06:33

2 Answers2

1

As long as there is just text inside the td this should work. I adapted this answer to your code, making the highlighting change and/or disappear appropriately as the search term changes. Read comments in the code for details. Run the snippet to test.

myFunction = function() {
  // Declare variables
  var input, filter, table, tr, td, i, txtValue, index;
  input = document.getElementById("myInput");
  filter = input.value.toUpperCase();
  table = document.getElementById("myTable");
  tr = table.getElementsByTagName("tr");

  // Loop through all table rows, and hide those who don't match the search query
  for (i = 0; i < tr.length; i++) {
    td = tr[i].getElementsByTagName("td")[0];
    if (td) {
      txtValue = td.textContent || td.innerText;

      // first clear any previously marked text
      // this strips out the <mark> tags leaving text (actually all tags)
      td.innerHTML = txtValue;

      index = txtValue.toUpperCase().indexOf(filter);
      if (index > -1) {

        // using substring with index and filter.length 
        // nest the matched string inside a <mark> tag
        td.innerHTML = txtValue.substring(0, index) + "<mark>" + txtValue.substring(index, index + filter.length) + "</mark>" + txtValue.substring(index + filter.length);

        tr[i].style.display = "";
      } else {
        tr[i].style.display = "none";
      }
    }
  }
}
#myInput {
  background-image: url('/css/searchicon.png');
  /* Add a search icon to input */
  background-position: 10px 12px;
  /* Position the search icon */
  background-repeat: no-repeat;
  /* Do not repeat the icon image */
  width: 100%;
  /* Full-width */
  font-size: 16px;
  /* Increase font-size */
  padding: 12px 20px 12px 40px;
  /* Add some padding */
  border: 1px solid #ddd;
  /* Add a grey border */
  margin-bottom: 12px;
  /* Add some space below the input */
}

#myTable {
  border-collapse: collapse;
  /* Collapse borders */
  width: 100%;
  /* Full-width */
  border: 1px solid #ddd;
  /* Add a grey border */
  font-size: 18px;
  /* Increase font-size */
}

#myTable th,
#myTable td {
  text-align: left;
  /* Left-align text */
  padding: 12px;
  /* Add padding */
}

#myTable tr {
  /* Add a bottom border to all table rows */
  border-bottom: 1px solid #ddd;
}

#myTable tr.header,
#myTable tr:hover {
  /* Add a grey background color to the table header and on hover */
  background-color: #f1f1f1;
}
<input type="text" id="myInput" onkeyup="myFunction()" placeholder="Search for names..">

<table id="myTable">
  <tr class="header">
    <th style="width:60%;">Name</th>
    <th style="width:40%;">Country</th>
  </tr>
  <tr>
    <td>Alfreds Futterkiste</td>
    <td>Germany</td>
  </tr>
  <tr>
    <td>Berglunds snabbkop</td>
    <td>Sweden</td>
  </tr>
  <tr>
    <td>Island Trading</td>
    <td>UK</td>
  </tr>
  <tr>
    <td>Koniglich Essen</td>
    <td>Germany</td>
  </tr>
</table>
Arleigh Hix
  • 9,990
  • 1
  • 14
  • 31
  • Last question, what if I have a "
    " for putting the number of results found? Where would I put that code in the javascript? Like this sample: http://prntscr.com/pd8qg1
    – Christine Jane Oct 01 '19 at 08:02
0

I rewrote the script to a simpler version using ES6 and allow highlighting in any column. Also I hide the tr if it does not have a match

Since the text is changed by the highlighting, I save the text in a data attribute the first time I match something in a cell

the code can handle ONE layer of HTML in a cell. So

<td><a href="">Text</a></td>

I reuse the HTML from the previous answer but added thead and tbody for the selectors

const hilite = (match) => `<span class="highlight">${match}</span>`;
const changeText = (str,filterRe) => {
  const fragment = document.createElement('div');
  fragment.innerHTML = str;
  // handle ONE level
  [...fragment.childNodes].forEach(node => {
    if (node.nodeType === 1) node.innerHTML = node.textContent.replace(filterRe, hilite);
    else {
      let text = node.textContent;
      const newNode = document.createElement('span');
      newNode.innerHTML = text.replace(filterRe, hilite);
      node.parentNode.replaceChild(newNode,node)
    }
  });
  return fragment.innerHTML;
};
window.addEventListener('DOMContentLoaded', () => {
  const trs = document.querySelectorAll('#myTable tbody tr');
  [...document.querySelectorAll('#myTable tbody tr td')].forEach(td => td.dataset.savecontent = td.innerHTML);
  document.getElementById('myInput').addEventListener('input', (e) => {
    const filter = e.target.value;
    const filterRe = filter.length === 0 ? "" : new RegExp(filter, "gi"); // create a regex from input
    trs.forEach(tr => {
      let tds = tr.querySelectorAll('td');
      tds.forEach(td => {
        let content = td.dataset.savecontent;
        td.innerHTML =  filterRe ? changeText(content,filterRe) : content;
      });
      tr.hidden = filter && !tr.querySelector('.highlight'); // show if there is a filter and the row has a match
    });
  });
});
td a { text-decoration: none; }
.highlight { color: red; }
#myInput {
  background-repeat: no-repeat;
  width: 100%;
  font-size: 16px;
  padding: 12px 20px 12px 40px;
  border: 1px solid #ddd;
  margin-bottom: 12px;
}

#myTable {
  border-collapse: collapse;
  width: 100%;
  border: 1px solid #ddd;
  font-size: 18px;
}

#myTable th,
#myTable td {
  text-align: left;
  padding: 12px;
}

#myTable tr {
  border-bottom: 1px solid #ddd;
}
<input type="text" id="myInput" placeholder="Search for text..">

<table id="myTable">
  <thead>
    <tr class="header">
      <th style="width:60%;">Name</th>
      <th style="width:40%;">Country</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Alfreds Futterkiste</td>
      <td>Germany</td>
      <td><a href="https://google.com/search?q=Alfreds+Futterkiste">Search Alfreds Futterkiste</a></td>    
      </tr>
    <tr>
      <td>Berglunds snabbköp</td>
      <td>Sweden</td>
      <td><a href="https://google.com/search?q=Berglunds+snabbköp">Search Berglunds snabbköp</a></td>    
    </tr>
    <tr>
      <td>Island Trading</td>
      <td>UK</td>
      <td><a href="https://google.com/search?q=Island+Trading">Search Island Trading</a></td>    </tr>
    <tr>
      <td>Königlich Essen</td>
      <td>Germany</td>
      <td><a href="https://google.com/search?q=Königlich+Essen">Search Königlich Essen</a></td>
    </tr>
    <tbody>
</table>
mplungjan
  • 169,008
  • 28
  • 173
  • 236