Пример кода ниже — он работает, но кажется неуклюжим.
clients
предоставляется из БД в виде json_encoded
массив объектов (в реальном приложении это несколько сотен элементов).
Задача: фильтровать список на основе пользовательского ввода, который может быть частично нечувствительной к регистру строкой code
или же name
.
Пользователь заранее знает, что id
или же name
is — это для того, чтобы быстро сократить список до возможных совпадений, чтобы избавить их от пролистывания сотен.
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="https://codereview.stackexchange.com/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="https://codereview.stackexchange.com/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 -->
Мне не нравится, что есть повторение в создании li element
а также url
— Я подумал о создании функции, а затем использовании ее в map
?
const generateListElement = (client_id, name) => `<li><a href="/clients/view/${client_id}">${name}</a></li>`;
...map((element) => generateListElement(element.id, element.name)
но это выглядит не намного лучше.
хороший, плохой, уродливый?
1 ответ
Удалите внешний if else
if (clients.length === 0) {
clientsList.innerHTML = '<li>No clients were found.</li>';
return;
}
Разделить const clients
Сделайте функцию. На данный момент clients
жестко запрограммирован, позже переписан для работы с объектом JSON. Вызов функции не изменится
const clients = fetchWhateverThatDataIs();
function fetchWhateverThatDataIs() {
return [{ 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" }];
}
Объекты организуют функциональность, а затем упрощают клиентский код
А Clients
объект будет инкапсулировать filter
а также HtmlList
.
function Clients (theClients) {
this.clients = theClients ? theClients : [];
this.isEmpty = function() { return this.clients.length === 0; }
this.HtmlList = function () {
return this.clients.map((element) =>
'<li><a href="/clients/view/'%20+%20element.id%20+%20'">' + element.name + '</a></li>'
).join("");
} //HtmlList
// intended as an event handler
this.filter = function (event) {
this.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/'%20+%20element.id%20+%20'">' + element.name + '</a></li>').join("");
} //filter
} //Clients
<li>
здание повторяется. Пока я склонен следовать моему правилу «повторил один раз — думай о рефакторинге, повторил дважды (или больше) — рефакторинг». В любом случае сначала убедитесь, что этот первоначальный рефакторинг работает.
это работает, но кажется неуклюжим
Уже нет.
document.addEventListener("DOMContentLoaded", function (event) {
const clients = new Clients(fetchWhateverThatDataIs());
const clientsList = document.getElementById("clientsList");
const search = document.getElementById("search");
if (clients.isEmpty()) {
clientsList.innerHTML = '<li>No clients were found.</li>';
return;
}
clientsList.innerHTML = clients.HtmlList();
search.addEventListener("keyup", clients.filter);
});