Как сдлеать фильтр с чекбоксами?
Есть фильтр на чекбоксах, нужно что-бы при клике на чекбокс показывался тот контент, который соответсвует фильтру. Как сделать так чтобы при переключении чекбокса оставались только те карточки, у которых есть фильтр(сейчас работает только если нажать чекбокс-отключить чекбокс)? Спасибо
document.querySelectorAll('.checkboxes').forEach((n) => {
n.addEventListener("change", onCheckBoxChange)
})
const blocks = Array.from(document.querySelectorAll(".filter__column")).map(
(block) => {
return {
node: block,
themes: Array.from(block.classList).filter((blockClass) =>
blockClass.includes("filter__checkbox_"),
),
}
},
)
const inputs = Array.from(document.querySelectorAll(".checkbox__input")).map(
(check) => {
return {
node: check,
theme: check.getAttribute("data-filter"),
}
},
)
//Функция которая будет вызываться при любом изменении чекбокса
function onCheckBoxChange() {
const checkedInput = inputs.filter((c) => c.node.checked)
if (checkedInput.length == 0) {
blocks.forEach((block) => {
block.node.classList.remove("_hidden-checkbox")
}) //если фильтров не выбрано, то отображаем все элементы
} else {
blocks.forEach((block) => {
block.node.classList.add("_hidden-checkbox")
}) // иначе скроем все элементы
let buffBlocks = [...blocks] // Здесь собираем только те блоки, которые содержат нужные темы
checkedInput.forEach((input) => {
buffBlocks = buffBlocks.filter((block) => {
return block.themes.includes(`filter__checkbox_${input.theme}`)
})
})
buffBlocks.forEach((block) =>
block.node.classList.remove("_hidden-checkbox"),
) //Отобразим блоки, которые соответствуют фильтру
}
}
.filter__column._hidden-checkbox{
display:none;
}
<div class="checkboxes">
<div class="checkbox__item">
<input
data-filter="filter_1"
id="c_1"
data-error="Ошибка"
class="checkbox__input"
type="checkbox"
value="1"
name="form[]"
/>
<label for="c_1" class="checkbox__label"
><span class="checkbox__text">Текст</span></label
>
<input
data-filter="filter_2"
id="c_1"
data-error="Ошибка"
class="checkbox__input"
type="checkbox"
value="1"
name="form[]"
/>
<label for="c_1" class="checkbox__label"
><span class="checkbox__text">Текст</span></label
>
</div>
<div class="checkbox__item">
<input
data-filter="filter_3"
id="c_3"
data-error="Ошибка"
class="checkbox__input"
type="checkbox"
value="3"
name="form[]"
/>
<label for="c_3" class="checkbox__label"
><span class="checkbox__text">Текст</span></label
>
<input
data-filter="filter_4"
id="c_4"
data-error="Ошибка"
class="checkbox__input"
type="checkbox"
value="4"
name="form[]"
/>
<label for="c_4" class="checkbox__label"
><span class="checkbox__text">Текст</span></label
>
</div>
</div>
<div class="filter-content">
<div
class="filter__column filter__checkbox_filter_1 filter__checkbox_filter_4"
>
Контент
</div>
<div class="filter__column filter__checkbox_filter_2">Контент</div>
<div class="filter__column filter__checkbox_filter_3">Контент</div>
<div
class="filter__column filter__checkbox_filter_4 filter__checkbox_filter_3"
>
Контент
</div>
</div>
Ответы (1 шт):
Простите, но ваш код мало того, что перегружен так ещё и нерабочий. Потому попробуем начать с нуля и сделать желаемое (:
Начнём с самих чекбоксов и того же addEventListener(change, ...)
. Зачем вы их все собираете и слушаете каждый по отдельности, если можно слушать родителя <div class="checkboxes">
?
const checkboxes = document.querySelector('.checkboxes');
checkboxes.addEventListener('change', e => {
console.log(e.target); // здесь будем реагировать.
});
Второе... Может я чего-то не понимаю, но зачем вам вообще сдалась эти константа blocks
? Да ещё и снаружи. Мало ли что может случиться в будущем и вдруг у вас там появятся новые динамические блоки (по дозагрузке). Если такое случится то поймёте. Есть вопрос и по константе inputs
... необходимость в ней существует лишь в том случае, если какой/какие-то из чекбоксов будут уже включен по умолчанию, а иначе она не нужна.
Перейдём к HTML
. Допускаю, что у вас есть далеко идущие планы на атрибуты чекбоксов и все эти классы и 'span', но ведь всё можно стилизовать от родителя, и поскольку я сейчас не вижу в них необходимости, то уберу всё лишнее.
const filter = document.querySelectorAll('.filter-content > div');
const checkboxes = document.querySelector('.checkboxes');
// слушаем все чекбоксы сразу
checkboxes.addEventListener('change', e => {
// получить состояние всех чекбоксов, которые нам понадобятся ниже
const status = [...checkboxes.querySelectorAll('[type="checkbox"]')].map(c => [c.value, c.checked] );
// если все чекбоксы сняты (false) то длина массива будет равна нулю.
const allFalse = status.reduce((acc,s) => {
if (s[1] === true) acc.push(s[1]);
return acc;
}, []);
if (allFalse.length === 0) {
// при нулевом состоянии удалем все .hide
Array.from(filter).map(item => {
item.classList.remove('hide');
});
} else {
// если хотя бы один чекбокс включён, то...
Array.from(filter).map(item => {
// сравниваем с текущим status-ом всех чекбоксов, и возвращаем boolean
// по сути всё решается именно здесь, в status.some()
const hide = status.some(el => {
if (item.classList.contains('filter_'+el[0])) return el[1] ;
});
// здесь от обратного (по отрицанию) удаляем или добавляем класс
if (!hide) {
item.classList.add('hide');
} else {
item.classList.remove('hide');
}
});
}
});
.hide {
display: none;
}
<div class="checkboxes">
<div>
<input type="checkbox" id="c_1" value="1" name="form[]"/><label for="c_1">Фильтр-1</label>
<input type="checkbox" id="c_2" value="2" name="form[]"/><label for="c_2">Фильтр-2</label>
</div>
<div>
<input type="checkbox" id="c_3" value="3" name="form[]"/><label for="c_3">Фильтр-3</label>
<input type="checkbox" id="c_4" value="4" name="form[]"/><label for="c_4">Фильтр-4</label>
</div>
</div>
<hr>
<div class="filter-content">
<div class="filter_1 filter_4">Контент (1,4)</div>
<div class="filter_2">Контент (2)</div>
<div class="filter_3">Контент (3)</div>
<div class="filter_4 filter_3">Контент (4,3)</div>
</div>
Как-то так... Можно было бы пойти и другими путями, но отталкивался от того, что имеем.