I created a working multiple tag filter with four <input type="checkbox">
which each have a tag which are also in my div
class (code below) but I have an issue when two checkboxes are selected.
None of my div
contains all four id
in their class name but they all appear on my screen when I select all checkboxes while none should appear.
Here is an example to illustrate my point :
<div class="filterDiv adobePhotoshop sketch"> Div1 </div>
<div class="filterDiv adobePhotoshop adobeIndesign"> Div2 </div>
When I check my "Adobe Photoshop" and "Sketch" checkboxes for instance, I have div1 and div2 appearing while I only want to make appear div1 (because div2 have adobePhotoshop too but NOT sketch).
Any idea of how can I manage this please?
Javascript :
const filterToggle = (e) => {
const checkedFilters = [...document.querySelectorAll('input[type=checkbox]:checked')].map(
(el) => el.id
),
toFilter = [...document.querySelectorAll('.filterDiv')];
if (checkedFilters.length === 0) {
toFilter.forEach(
(el) => el.style.display = 'flex'
)
} else {
toFilter.forEach(
(el) => el.style.display = 'none'
);
let selector = checkedFilters.map(
(f) => `.filterDiv.${f}`
).join(',');
document.querySelectorAll(selector).forEach(
(el) => el.style.display = 'flex'
);
};
};
filters = document.querySelectorAll('input[type=checkbox]');
filters.forEach(
(f) => f.addEventListener('change', filterToggle)
);
HTML :
<div id="btn-container">
<input type="checkbox" id="adobePhotoshop"> <label for="adobePhotoshop">Adobe Photoshop</label>
<input type="checkbox" id="adobeIndesign"> <label for="adobeIndesign">Adobe Indesign</label>
<input type="checkbox" id="adobeIllustrator"> <label for="adobeIllustrator">Adobe Illustrator</label>
<input type="checkbox" id="sketch"> <label for="sketch">Sketch</label>
</div>
<div class="grid-container">
<div class="filterDiv adobePhotoshop adobeIndesign adobeIllustrator">
Project1
</div>
<div class="filterDiv adobeIndesign adobeIllustrator">
Project2
</div>
<div class="filterDiv adobePhotoshop">
Project3
</div>
<div class="filterDiv adobePhotoshop sketch">
Project4
</div>
</div>
CSS :
.grid-container {
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: 1fr;
grid-gap: 60px;
}
.filterDiv {
display: flex;
height: 100%;
width: 100%;
}
let selector = checkedFilters.map(
(f) => `.filterDiv.${f}`
).join(',');
Let's assume the "adobePhotoshop" and "sketch" were checked. The code above should generate an array of class names selector:
[".filterDiv.adobePhotoshop", ".filterDiv.sketch"]
... which is used to select elements using:
document.querySelectorAll(selector).forEach(
(el) => el.style.display = 'flex'
);
... which is mimicking the OR condition, where it will select elements that have at least one of them (".filterDiv.adobePhotoshop"
or ".filterDiv.sketch"
) in the class names.
In order to make the filtering to be the AND condition, then the selector logic should be:
let selector = `.filterDiv.${checkedFilters.join('.')}`;
... to generate class name selector that only select elements that have all of the conditions:
.filterDiv.adobePohotoshop.sketch