Как сдлеать фильтр с чекбоксами?

Есть фильтр на чекбоксах, нужно что-бы при клике на чекбокс показывался тот контент, который соответсвует фильтру. Как сделать так чтобы при переключении чекбокса оставались только те карточки, у которых есть фильтр(сейчас работает только если нажать чекбокс-отключить чекбокс)? Спасибо

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 шт):

Автор решения: stylok

Простите, но ваш код мало того, что перегружен так ещё и нерабочий. Потому попробуем начать с нуля и сделать желаемое (:

Начнём с самих чекбоксов и того же 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>

Как-то так... Можно было бы пойти и другими путями, но отталкивался от того, что имеем.

→ Ссылка