Reputation: 3
I want the search bar to search for a topic (e.g.: cat) and when the topic is clicked ('cat') it takes me to the same page as the one referenced in the name list within the unordered list (e.g.:cat.html). The array from the search bar is generated from the list items within the unordered lists.
Also, when I use the search box, "search-list" causes the header to adjust which I don't want to happen. I would prefer if the "search-list" is apart from the search bar. This is what I've tried so far:
HTML:
<header>
<div>
<form autocomplete="off">
<input id="input" type="text">
<ul class="search-list"></ul>
</form>
</div>
</header>
<div id="wrapper">
<div class="name-list">
<ul class="names">
<li class="name"><a href="cat.html">Cat</a></li>
<li class="name"><a href="dog.html">Dog</a></li>
<li class="name"><a href="frog.html">Frog</a></li>
<li class="name"><a href="horse.html">Horse</a></li>
</ul>
</div>
<div class="name-list">
<ul class="names">
<li class="name"><a href="rabbit.html">Rabbit</a></li>
<li class="name"><a href="turtle.html">Turtle</a></li>
<li class="name"><a href="whale.html">Whale</a></li>
<li class="name"><a href="worm.html">Worm</a></li>
</ul>
</div>
</div>
JavaScript:
let list = document.getElementById('wrapper').getElementsByTagName('li');
let data = [];
for(let i = 0; i < list.length; i++){
data.push(list[i].innerText);
}
let jsonFormated = Array.from(data);
let sortedList = jsonFormated.sort()
console.log(list)
console.log(jsonFormated)
console.log(sortedList)
let searchInput = document.getElementById('input');
// execute function on key up
searchInput.addEventListener('keyup', (e) => {
removeElements();
for(let i of sortedList){
if(i.toLowerCase().startsWith(searchInput.value.toLowerCase()) && searchInput.value != ''){
// create list element
let listItem = document.createElement("li");
// one common class name
listItem.classList.add("list-items");
listItem.style.cursor = 'pointer';
listItem.setAttribute('onclick', "displayNames('" + i + "')");
// display matched part in bold
let word = "<b>" + i.substring(0,searchInput.value.length) + "</b>";
word+= i.substring(searchInput.value.length);
// display the value in array
listItem.innerHTML = word;
document.querySelector('.search-list').appendChild(listItem);
}
}
});
function displayNames(value){
searchInput.value = value;
removeElements();
}
function removeElements(){
// clear all the items
let items = document.querySelectorAll('.list-items');
items.forEach((item) => {
item.remove();
})
}
Upvotes: 0
Views: 605
Reputation: 11417
When you iterate the li
elements and push the data into the array, you also lose a hard reference to the element to be able to get the link to copy into the new search results list items.
You could populate a list of objects that has both the item name and the link, but that's probably overkill. In the below solution, we instead iterate over the whole element list, which means it's easy to get the href from the list of the original names and then use it to create a new link. The intermediary data
var is not needed.
let searchInput = document.getElementById("input");
const sortedElements = [
...document.getElementById("wrapper").getElementsByTagName("li")
].sort(function (a, b) {
var textA = a.innerText;
var textB = b.innerText;
if (textA < textB) return -1;
if (textA > textB) return 1;
return 0;
});
// execute function on key up
searchInput.addEventListener("keyup", (e) => {
removeElements();
for (let i of sortedElements) {
if (
i.innerText.toLowerCase().startsWith(searchInput.value.toLowerCase()) &&
searchInput.value != ""
) {
// create list element
let listItem = document.createElement("li");
// one common class name
listItem.classList.add("list-items");
listItem.style.cursor = "pointer";
let link = document.createElement("a");
link.setAttribute("href", i.querySelector("a").getAttribute("href"));
listItem.appendChild(link);
// display matched part in bold
let word =
"<b>" + i.innerText.substring(0, searchInput.value.length) + "</b>";
word += i.innerText.substring(searchInput.value.length);
// display the value in array
link.innerHTML = word;
document.querySelector(".search-list").appendChild(listItem);
}
}
});
function displayNames(value) {
searchInput.value = value;
removeElements();
}
function removeElements() {
// clear all the items
let items = document.querySelectorAll(".list-items");
items.forEach((item) => {
item.remove();
});
}
The second half of your question would require seeing the CSS. If you want it to overlay, you'll need to use a combination of position relative and position absolute in the right places.
Upvotes: 1