Sample code below - it works, but feels clunky.
clients is provided from a DB as a json_encoded array of objects (in the real app this is several hundred items.)
Objective: filter the list based on user input, which can be a partial case-insensitive string of code or name.
The user knows in advance what the id or name is - this is to quickly reduce the list to possible matches, to save them from scrolling through hundreds.
document.addEventListener("DOMContentLoaded", function (event) {
const clients = [{ id: 1, name: "Bob Marley", code: "BM1" }, { id: 2, name: "Elton John", code:"EJ1" }, { id: 3, name: "Beach Boys", code: "BB1" }, { id: 4, name: "Boyzone", code: "BO1" }];
const clientsList = document.getElementById("clientsList");
const search = document.getElementById("search");
// handle empty client array?
if (clients.length === 0) {
clientsList.innerHTML = '<li>No clients were found.</li>';
} else {
// populate the list initially
const listArray = clients.map((element) =>
'<li><a href="/clients/view/' + element.id + '">' + element.name + '</a></li>'
).join("");
clientsList.innerHTML = listArray;
search.addEventListener("keyup", function (event) {
clientsList.innerHTML = clients.filter((value) =>
value.name.toLowerCase().includes(event.target.value.toLowerCase()) ||
value.code.toLowerCase().includes(event.target.value.toLowerCase())
).map((element) =>
'<li><a href="/clients/view/' + element.id + '">' + element.name + '</a></li>').join("");
});
}
});
<input type="text" id="search" placeholder="Search...">
<ul id="clientsList"></ul>
<!-- Sample input / output
bo => bob marley, beach boys, boyzone
on => elton john, boyzone
bm1 => bob marley -->
I don't like that there is repetition in generating the li element and url - I thought about creating a function and then using that in the map?
const generateListElement = (client_id, name) => `<li><a href="/clients/view/${client_id}">${name}</a></li>`;
...map((element) => generateListElement(element.id, element.name)
but that doesn't look much better.
good, bad, ugly?