Reputation: 230
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
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
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
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