Reputation: 55
I'm trying to make a search bar. No matter what I type in search box it shows the "Dropdown" as result and it doesn't show the items inside that list when I search. What am I doing wrong? https://jsfiddle.net/5xh86fkn/
var dropdown = document.getElementsByClassName("dropdown-btn");
var i;
for (i = 0; i < dropdown.length; i++) {
dropdown[i].addEventListener("click", function() {
this.classList.toggle("active");
var dropdownContent = this.nextElementSibling;
if (dropdownContent.style.display === "block") {
dropdownContent.style.display = "none";
} else {
dropdownContent.style.display = "block";
}
});
}
function myFunction() {
var input, filter, ul, li, a, i;
input = document.getElementById("mySearch");
filter = input.value.toUpperCase();
ul = document.getElementById("myMenu");
li = ul.getElementsByTagName("li");
for (i = 0; i < li.length; i++) {
a = li[i].getElementsByTagName("a")[0];
if (a.innerHTML.toUpperCase().indexOf(filter) > -1) {
li[i].style.display = "";
} else {
li[i].style.display = "none";
}
}
}
<div class="sidenav">
<input type="text" id="mySearch" onkeyup="myFunction()" placeholder="Search.." title="Type in a category">
<ul id="myMenu">
<li><a href="#about">About</a></li>
<li><a href="#services">Services</a></li>
<li><a href="#clients">Clients</a></li>
<li><a href="#contact">Contact</a></li>
<button class="dropdown-btn">Dropdown
<i class="fa fa-caret-down"></i>
</button>
<div class="dropdown-container">
<li><a href="#">Link 1</a></li>
<li><a href="#">Link 2</a></li>
<li><a href="#">Link 3</a></li>
</div>
<li><a href="#contact">Search</a></li>
</ul>
</div>
Upvotes: 4
Views: 4040
Reputation: 34227
For simplicity I removed code not related to the Search question.
I would suggest a slightly different approach here.
textContent
of the nodes so that you would not match the HTML other than that.a
that is directly inside an li
by using li>a
- I would strongly suggest classes instead of element selectors however for the "searchable" elements.li
by a toggle of the dataset valueNote this code can be further reduced but I left it verbose for clarity.
document.getElementById("mySearch").addEventListener('keyup', (event) => {
const findMe = event.target.value.toUpperCase();
const searchable = document.querySelectorAll('li>a');
searchable.forEach(function(searchItem) {
searchItem.parentElement.dataset.isfound = searchItem.textContent.toUpperCase().includes(findMe) ? "true" : "false";
});
});
li[data-isfound="true"] {
background-color: yellow;
}
li[data-isfound="false"] {
display: none;
}
<div class="sidenav">
<input type="text" id="mySearch" placeholder="Search.." title="Type in a category">
<ul id="myMenu">
<li><a href="#about">About</a></li>
<li><a href="#services">Services</a></li>
<li><a href="#clients">Clients</a></li>
<li><a href="#contact">Contact</a></li>
<li><button class="dropdown-btn">Dropdown
<i class="fa fa-caret-down"></i>
</button></li>
<ul class="dropdown-container">
<li><a href="#">Link 1</a></li>
<li><a href="#">Link 2</a></li>
<li><a href="#">Link 3</a></li>
</ul>
<li><a href="#contact">Search</a></li>
</ul>
</div>
Upvotes: 0
Reputation: 8196
This is a working demo of your attempt of filtering the menu items in real time by typing suggestions on the input text.
The main problem was using the correct strategy to fetch the menu items from dom. The element you wanted to partecipate in the filtering, wasn't a <LI>
element.
Plus the list you embedded inside the Dropdown button wasn't included in a ol container and was breaking the correct behaviour.
I slightly refactored your html and focused on the single js function in charge of filtering the list according to the input typed:
function f(filter){
menuItems = document.querySelectorAll('#myMenu > li');
for(const menuItem of menuItems){
const textContent = menuItem.textContent.trim().toUpperCase();
//console.log(`"${textContent}" "${filter}" "${textContent.indexOf(filter)}"`);
if (textContent.indexOf(filter.toUpperCase()) > -1) {
menuItem.classList.remove('hidden');
}else{
menuItem.classList.add('hidden');
}
}
}
.hidden{
display: none;
}
body {
font-family: "Lato", sans-serif;
}
/* Fixed sidenav, full height */
.sidenav {
height: 100%;
width: 200px;
position: fixed;
z-index: 1;
top: 0;
left: 0;
background-color: #111;
overflow-x: hidden;
padding-top: 20px;
}
/* Style the sidenav links and the dropdown button */
.sidenav a, .dropdown-btn {
padding: 6px 8px 6px 16px;
text-decoration: none;
font-size: 20px;
color: #818181;
display: block;
border: none;
background: none;
width: 100%;
text-align: left;
cursor: pointer;
outline: none;
}
/* On mouse-over */
.sidenav a:hover, .dropdown-btn:hover {
color: #f1f1f1;
}
/* Main content */
.main {
margin-left: 200px; /* Same as the width of the sidenav */
font-size: 20px; /* Increased text to enable scrolling */
padding: 0px 10px;
}
/* Add an active class to the active dropdown button */
.active {
background-color: green;
color: white;
}
/* Dropdown container (hidden by default). Optional: add a lighter background color and some left padding to change the design of the dropdown content */
.dropdown-container {
display: none;
background-color: #262626;
padding-left: 8px;
}
/* Optional: Style the caret down icon */
.fa-caret-down {
float: right;
padding-right: 8px;
}
/* Some media queries for responsiveness */
@media screen and (max-height: 450px) {
.sidenav {padding-top: 15px;}
.sidenav a {font-size: 18px;}
}
<div class="sidenav">
<input type="text" id="mySearch" onkeyup="f(this.value)" placeholder="Search.." title="Type in a category">
<ul id="myMenu">
<li><a href="#about">About</a></li>
<li><a href="#services">Services</a></li>
<li><a href="#clients">Clients</a></li>
<li><a href="#contact">Contact</a></li>
<li>
<button class="dropdown-btn">
Dropdown
<i class="fa fa-caret-down"></i>
</button>
<div class="dropdown-container">
<ol>
<li><a href="#">Link 1</a></li>
<li><a href="#">Link 2</a></li>
<li><a href="#">Link 3</a></li>
</ol>
</div>
</li>
<li>
<a href="#contact">Search</a>
</li>
</ul>
</div>
Upvotes: 1