Home > database >  Search bar with dropdown list
Search bar with dropdown list

Time:07-22

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 >
  <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 >Dropdown 
        <i ></i>
      </button>
    <div >
      <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>

CodePudding user response:

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 >
  
  <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 >
        Dropdown
        <i ></i>
      </button>
      <div >
        <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>

CodePudding user response:

For simplicity I removed code not related to the Search question.

I would suggest a slightly different approach here.

  • Use the textContent of the nodes so that you would not match the HTML other than that.
  • Leverage the data attribute and some CSS to make the code smaller by setting them to a true/false string and show/hide based upon that.
  • Use a descender selector to find only 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.
  • Note I hide the parent li by a toggle of the dataset value
  • I removed the JavaScript from the HTML as a best practice

Note 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 >
  <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 >Dropdown 
        <i ></i>
      </button></li>
    <ul >
      <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>

  • Related