Home > Mobile >  Multiple word search feature HTML list filter
Multiple word search feature HTML list filter

Time:09-16

I have a search feature which uses JavaScript to filter a html list.

All list items are hidden by default but show if the user inputs the right keywords.

At the moment the search only returns items which match the input exactly.

If a word is missed, additional word added or order of words differ, the result isn’t shown.

I’d like the user to be able to search multiple words, and if one or more of the words match, the result is shown.

It should not matter which order the user inputs the words.

For example, searching ‘VAUXHALL CORSA DIESEL’ would return the list item, ‘BLUE VAUXHALL CORSA 1.6L DIESEL.’

Searching ‘DIESEL VAUXHALL’ would also return the same list item.

I figured this could be done by incorporating .split(“ ”), however I am unsure at what point in the code it is needed.

I’ve tried a few configurations to no avail.

I’m very new to coding!

I’ve added the current script.

window.addEventListener("load", () => {
  var filter = document.getElementById("filter"),
    list = document.querySelectorAll(".list li");
  filter.onkeyup = () => {
    let search = filter.value.toLowerCase();
    for (let i of list) {
      let item = i.innerHTML.toLowerCase();
      if (item.indexOf(search) == -1) {
        i.classList.add("hide");
      } else {
        i.classList.remove("hide");
        if (filter.value.length == 0) {
          i.classList.add("hide");
        }
      }
    }
  };
});

CodePudding user response:

You can split the search with empty space.

For example

let searchKeywords = filter.value.toLowerCase().split(" ");

and with every array function check the item if contains every keyword in the search.

Full example of code.

window.addEventListener("load", () => {
  var filter = document.getElementById("filter"),
    list = document.querySelectorAll(".list li");
  filter.onkeyup = () => {
    let searchKeywords = filter.value.toLowerCase().split(" ");
    for (let i of list) {
      let item = i.innerHTML.toLowerCase();
      if (searchKeywords.every(word => item.includes(word))) {
        i.classList.add("hide");
      } else {
        i.classList.remove("hide");
        if (filter.value.length == 0) {
          i.classList.add("hide");
        }
      }
    }
  };
});

CodePudding user response:

I guessed some HTML

This does what you ask using .every and .includes

I also use on input instead since the user can paste into the field Lastly I simplified the hiding

window.addEventListener("load", () => {
  const list = document.querySelector(".list")
  filter = document.getElementById("filter"),
    lis = [...list.querySelectorAll("li")]; // spread to use map and sort
  filter.addEventListener("input", () => {
    let search = filter.value.toLowerCase().split(/\W /);
    lis.forEach(li => {
      if (search.length === 0) {
        li.hidden = true;
        li.dataset.rank = 0;
        return
      }
      let items = li.textContent.toLowerCase().split(/\W /)
      li.hidden = !search.every(flt => items.includes(flt))
      li.dataset.rank = search.filter(flt => items.includes(flt)); // how many
    });
    lis.sort((a, b) => a.dataset.rank - b.dataset.rank).forEach(li => list.append(li))
  });
});
For example, searching ‘VAUXHALL CORSA DIESEL’ would return the list item, Searching ‘DIESEL VAUXHALL’ would also return the same list item.
<hr/>
<input type="text" id="filter" />
<ul >
  <li>BLUE VAUXHALL CORSA 1.6L DIESEL</li>
  <li>RED DIESEL</li>
  <li>GREEN VAUXHALL ASTRA 1.6L PETROL</li>
  <li>RED VAUXHALL CORSA 1.6L DIESEL</li>
  <li>RED VAUXHALL CORSA 1.6L PETROL</li>
  <li>RED VAUXHALL ASTRA 1.6L PETROL</li>
  <li>RED VAUXHALL ASTRA 1.6L DIESEL</li>

</ul>

  • Related