Setup
Judging by the code you've shared, you're probably not using es6 or a js bundler to setup your project. This means no import
s and the library <scrpit>
s go inside your index.html
Steps
- Verify you are loading the script correctly
- Clean up the code
- separate it to chunks to better understand what's failing
- Update the code with the highlight functionality described by the "getting started" of the package
Notes
With the mark.js
library it would be best to clean up the mark (.unmark()
) before applying it again. because it will add more elements on each change. That's why we keep a single instance of mark per context (context is the table element) instead of creating a new instance inside the highlightChanges
function
The snippet below is not the optimal implementation of this functionality but it can serve for a starting point. It was based on the original code
Snippet with added highlight
var input, table, rows, markInstance;
window.onload = function init() {
input = document.getElementById("myInput");
table = document.getElementById('myTable');
rows = table.querySelectorAll('tr');
markInstance = new Mark(table);
clear();
}
function ContactsearchFX() {
clear();
if (input.value.length == 0) return;
filterRows(input.value);
highlightMatches(input.value);
}
function clear() {
markInstance.unmark();
for (var i = 0; i < rows.length; i++) {
rows[i].style.display = 'none';
}
}
function filterRows(text) {
var part = text.toUpperCase();
for (i = 0; i < rows.length; i++) {
var row = rows[i];
var td = row.getElementsByTagName("td")[0];
if (td) {
// part = GI
// innerHtml = <MARK DATA-MARKJS="TRUE">G</MARK>ITHUB (wont match)
// innerText = GITHUB (will match)
var content = td.innerText.toUpperCase();
if (content.includes(part)) {
row.style.display = "";
}
}
}
}
function highlightMatches(text) {
markInstance.mark(text);
}
.input-wrap {
margin-bottom: 12px;
}
.hints {
display: none;
margin-top: 12px;
}
#myInput:invalid~.hints {
display: block;
}
mark {
background: orange;
font-weight: bold;
color: black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/mark.js/8.11.1/mark.js"></script>
<div class="input-wrap">
<label>
Search Titles:
<input id="myInput" type="text" required
onkeyup="ContactsearchFX()"
placeholder="Search Titles" />
<span class="hints">
Hints: type "git", "bit", "forge" ...
</span>
</label>
</div>
<table id="myTable" style="width: 100%" class="style1">
<tr>
<th>Title</th>
<th>Description</th>
</tr>
<tr>
<td>Github</td>
<td>Is the HUB</td>
</tr>
<tr>
<td>Gitlab</td>
<td>Have nice CI</td>
</tr>
<tr>
<td>Bitbucket</td>
<td>Has Jira integration (Duh)</td>
</tr>
<tr>
<td>SourceForge</td>
<td>Open source projects live here. It is said</td>
</tr>
</table>
And a more appropriate version for production
Quick look through the examples and the API for the options
parameter of the mark()
function review that we can substitute most of the logic with the hooks from the options
The input event handler is debounce
ed (function from from lodash
_.debounce
) this way the filtering will start when the user stops typing (for more than 250ms)
Content is again .unmark()
ed at the start - the different part is that we use the options parameter with a done
callback to continue with highlightMatches
when unmark
finishes
The options parameter have an each
prop which is a callback for each element that matches. Using this callback we can search for it's parent that we know must be a row, and we add a class show
so the row can become visible.
There's also a noMatch
prop which will be called (back) if the texts matches nothing so we can show some hint to maybe try a different text
The options parameter hold other useful props that can configure the matching like, wildcards, case sensitive matching and so on...
var input, table, rows, noMatches, markInstance;
window.onload = function init() {
input = document.getElementById('myInput');
noMatches = document.getElementById('noMatches');
table = document.getElementById('myTable');
rows = table.querySelectorAll('tr');
markInstance = new Mark(table);
input.addEventListener('keyup', _.debounce(ContactsearchFX, 250));
}
function ContactsearchFX() {
resetContent();
markInstance.unmark({
done: highlightMatches
});
}
function resetContent() {
noMatches.textContent = '';
rows.forEach(function(row) {
row.classList.remove('show');
});
}
function highlightMatches() {
markInstance.mark(input.value, {
each: showParantRow,
noMatch: onNoMatches,
})
}
function showParantRow(element) {
var row = element.closest('tr');
row.classList.add('show');
}
function onNoMatches(text) {
noMatches.textContent = 'No records match: "' + text + '"';
};
.input-wrap {
margin-bottom: 12px;
}
#myInput:invalid~.hints {
display: block;
}
#noMatches:empty, #noMatches:empty + .hints {
display: none;
}
.filterTable tr {
display: none;
}
.filterTable .show {
display: table-row;
}
mark {
background: orange;
font-weight: bold;
color: black;
}
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.11/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mark.js/8.11.1/mark.min.js"></script>
<div class="input-wrap">
<label>
Search Titles:
<input id="myInput" type="text" required
placeholder="Search Titles" />
</label>
</div>
<div class="hintsWrap">
<p id="noMatches"></p>
<p class="hints">
Hints: type "git", "bit", "forge" ...
</p>
</div>
<table id="myTable" style="width: 100%" class="filterTable">
<tr>
<td>Github</td>
<td>Is the HUB</td>
</tr>
<tr>
<td>Gitlab</td>
<td>Have nice CI</td>
</tr>
<tr>
<td>Bitbucket</td>
<td>Has Jira integration (Duh)</td>
</tr>
<tr>
<td>SourceForge</td>
<td>Open source projects live here. It is said</td>
</tr>
</table>