Might be an overkill approach. But this how I got it working.
The technique:
1- Get the original table (as a whole DOM) into a JS variable
2- Clone that variable into another JS variable.
3- The clone is used as a reference. Will remain intact never be modified.
4- The highlight works by extracting the found phrase, wrap with a <span>
having that span is given a certain CSS to stand out from the rest of the text.
The reason behind this is that, if we edit the original table, and then we try to search again, the HTML tag that got inserted will be included in the searched terms and therefore, the search will break down.
We will be searching the clone always, then will get the text from the clone, process it, and then apply the new processed phrase to the original table. In other words, If the searched phrase is found in the clone object, its content will be copied over to the original table.
If I were to do this again, I would replace the whole thing with JQuery. But anyhow, this code needs to be optimized.
var originalTable = document.getElementById("myTable");
var realTr = originalTable.getElementsByTagName("tr");
var cloneTable = originalTable.cloneNode(true);
var cloneTr = cloneTable.getElementsByTagName("tr");
function myFunction() {
var input, filter, cloneTd, cloneTdValue, realTd, i, inputValue, inputValueUpper;
input = document.getElementById("myInput");
inputValue = input.value;
inputValueUpper = inputValue.toUpperCase();
for (i = 0; i < cloneTr.length; i++) {
cloneTd = cloneTr[i].getElementsByTagName("td")[0];
if (cloneTd) {
var cloneTdValue = cloneTd.innerHTML;
var cloneTdValueUpper = cloneTdValue.toUpperCase();
var index = cloneTdValueUpper.indexOf(inputValueUpper);
if (index > -1) {
var newStr = wrapStuff(inputValue, cloneTdValue, index);
realTr[i].style.display = "";
realTd = realTr[i].getElementsByTagName("td")[0];
realTd.innerHTML = newStr;
} else {
realTr[i].style.display = "none";
}
}
}
}
function wrapStuff(input, tdStr, index) {
if (input.length === 0)
{
return tdStr;
}
var before, after, searched, extractLen, extractedVal, newString;
extractLen = index + input.length;
before = tdStr.substring(0, index);
after = tdStr.substring(extractLen, tdStr.length);
var newIndex = after.indexOf(input);
//Recursive function: yeah, my head got spinning.
//this is to apply the same code to the second half of the spliced string, because indexOf will only find the first occurance.
if (newIndex > -1) {
after = wrapStuff(input, after, newIndex);
}
extractedVal = tdStr.substring(index, extractLen);
newString = before + "<span class=\"highlight\">" + extractedVal + "</span>" + after;
return newString;
}
* {
box-sizing: border-box;
}
#myInput {
background-image: url('/css/searchicon.png');
background-position: 10px 10px;
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;
}
#myTable tr.header, #myTable tr:hover {
background-color: #f1f1f1;
}
.highlight {
color: red;
}
<body>
<h2>My Customers</h2>
<input type="text" id="myInput" onkeyup="myFunction()" placeholder="Search for names.." title="Type in a name">
<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>
<tr>
<td>Laughing Bacchus Winecellars</td>
<td>Canada</td>
</tr>
<tr>
<td>Magazzini Alimentari Riuniti</td>
<td>Italy</td>
</tr>
<tr>
<td>North/South</td>
<td>UK</td>
</tr>
<tr>
<td>Paris specialites</td>
<td>France</td>
</tr>
</table>
<script>
</script>
</body>