zyyyzzz
zyyyzzz

Reputation: 230

Filter select option dropdown when user clicks

So I want to filter select option dropdown based on what user clicks by id:

document.querySelectorAll('#item-types').forEach(item => {
        item.addEventListener('click', () => {
            const categoriesSelect = document.querySelector('#item-categories')
            const categoriesOptions = Array.from(categoriesSelect.options);
            const selectType = item.dataset.typeId;

            function findMatches(search, categoriesOptions) {
                return categoriesOptions.filter(option => {
                    return option.value.match(search);
                });
            }

            categoriesOptions.forEach(option => {
                option.remove();
                option.selected = false;
            });
            const matchArray = findMatches(selectType, categoriesOptions);
            categoriesSelect.append(...matchArray);
        });
    });
<ul>
   <li id="item-types" data-type-id="1">
       <a href="#">
           <div>Type1</div>
       </a>
   </li>
   <li id="item-types" data-type-id="2">
       <a href="#">
           <div>Type2</div>
       </a>
   </li>
</ul>

<select id="item-categories">
    <option value="1">category1</option>
    <option value="1">category2</option>
    <option value="1">category3</option>
    <option value="2">category4</option>
    <option value="2">category5</option>
</select>

But now when I click any of the list items for the first item it filters out okay, but when I click it second time it returns empty array for options.

Upvotes: 0

Views: 670

Answers (3)

navnath
navnath

Reputation: 3714

 const allCategoryOptionsStore = [...document.getElementById("item-categories").options];
  // parent event listener
  document.getElementById("types").addEventListener("click", handleOnClick);

  function handleOnClick(e){
    var tgt = e.target;
    if (tgt.tagName.toUpperCase() == "DIV") {
      const dataTypeId = tgt.parentElement.parentElement.getAttribute("data-type-id");
      const selectCategories = document.getElementById("item-categories");
      selectCategories.options.length = 0;
      allCategoryOptionsStore.filter(opt => opt.value === dataTypeId).forEach(opt =>selectCategories.options.add(opt));
    }
  }
<ul id="types">
  <li data-type-id="1">
    <a>
      <div>Type 1</div>
    </a>
  </li>
  <li data-type-id="2">
    <a>
      <div>Type 2</div>
    </a>
  </li>
  <li data-type-id="3">
    <a>
      <div>Type 3</div>
    </a>
  </li>
  <li data-type-id="4">
    <a>
      <div>Type 4</div>
    </a>
  </li>
</ul>

<select id="item-categories">
  <option value="1">category 1</option>
  <option value="2">category 2</option>
  <option value="2">category 2</option>
  <option value="3">category 3</option>
  <option value="3">category 3</option>
  <option value="1">category 1</option>
  <option value="4">category 4</option>
</select>

Upvotes: 0

mplungjan
mplungjan

Reputation: 178401

Have a go with this

I save the options and add them when clicked

I also simplified your UL. You could add a cursor:pointer to it if you need

I am not hiding the options because it is poorly supported

How can I hide select options with JavaScript? (Cross browser)

const categoriesSelect = document.getElementById('item-categories')
const originalOptions = [...categoriesSelect.options].slice(0); // copy
document.getElementById('item-types').addEventListener('click', (e) => {
  const tgt = e.target.closest("li");
  if (tgt.classList.contains("item-type")) {
    const selectType = tgt.dataset.typeId;
    categoriesSelect.length=0; // remove all
    originalOptions.filter(opt => opt.value == selectType).forEach(opt => categoriesSelect.append(opt))
  }
  categoriesSelect.selectedIndex = 0; // select the first
});
<ul id="item-types">
  <li class="item-type" data-type-id="1">Type1</li>
  <li class="item-type" data-type-id="2">Type2</li>
</ul>

<select id="item-categories">
  <option value="1">category1</option>
  <option value="1">category2</option>
  <option value="1">category3</option>
  <option value="2">category4</option>
  <option value="2">category5</option>
</select>

Upvotes: 1

tuomokar
tuomokar

Reputation: 388

Your issue seems to be that you remove the options completely if they don't fit the search criteria and then when you filter again, you filter from the ones already previously filtered. Because of that you get the empty array.

Instead you need to come up with a way to remember the initial options and filter always from those. You could store the options in a variable for example. Or simply hide the non-matching ones with CSS instead of removing them completely.

Upvotes: 0

Related Questions