Roe
Roe

Reputation: 3

How can I get search bar results to take me to the same page as the listed items within the body?

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

Answers (1)

adsy
adsy

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

Related Questions