@Singme

Множественная фильтрация DOM на JS Vanilla?

Дамы и господа, прошу совета. В пример кода выложил фильтр, где есть два споллера, которые должны фильтровать коллекцию li.

Если нажать на первый и выбрать класс, то он отфильтрует, когда нажмёшь на пункт второго споллера - всё сработает, как и должно.

Но если мы выберем ещё раз пункт из второго споллера, то список полностью обнулится, так как выборка делается из существующего списка. Если я сделаю, чтобы он обновлял список, как в первом споллере, то он перестанет фильтровать на основе первого и будет выдавать всегда только список всех предметов не учитывая класс. Как можно пофиксить этот момент? Буду крайне признателен за подсказку.

const filterLiCollection = document.querySelectorAll(".exTasksLi");

document.querySelectorAll(".filter-spoller-classes").forEach((e) => {

  e.addEventListener("click", (eve) => {

    let classItem = e.classList[0].split("-")[3];

    sortLis(classItem);

  }),

    false;

});

 

function sortLis(item) {

  filterLiCollection.forEach((e) =>

    e.getAttribute("data-class")

      ? (e.style.display = "block")

      : console.log("q")

  );

  let result = [...filterLiCollection].filter(

    (e) => e.getAttribute("data-class") !== item && e.style.display == "block"

  );

  result.forEach((e) => (e.style.display = "none"));

}

document.querySelectorAll(".filter-spoller-a-subject").forEach((e) =>

  e.addEventListener("click", (eve) => {

    let subjectItem = e.classList[0].split("-")[3];

    sortSubjects(subjectItem);

  })

);

 

function sortSubjects(subjectItem) {

  filterLiCollection.forEach((e) => {

    let result = [...filterLiCollection].filter(

      (e) => e.getAttribute("data-subject") !== subjectItem

    );

    result.forEach((e) => (e.style.display = "none"));

  });

}
  • Вопрос задан
  • 174 просмотра
Пригласить эксперта
Ответы на вопрос 1
@Singme Автор вопроса
Господа, пришёл к ответу.

// Получаем все 18 строчек li. Преобразовываем NodeList в массив, чтобы работали функции высшего порядка (filter, forEach, Map, Reduce)
let filterLiCollection = [...document.querySelectorAll(".exTasksLi")];
 
// Здесь мы получаем 10 кнопок, пробегаемся через forEach и ставим слушатель на click.
//Чтобы знать, как поступать с той или иной кнопкой, идентифицировать её, мы получаем класс, который на каждой кнопке свой, он выглядит так (filter-spoller-a-9-class) на кнопках с классами, и так (filter-spoller-a-math-subject) на кнопках с предметами. С помощью split делим строку по дефисам и берём из массива слово/цифру, в зависимости от кнопки.
//С помощью тернарного оператора проверяем этот символ и вызываем функцию, аргументов передавая это значение
document.querySelectorAll(".filter-spoller-a-all").forEach((e) => {
  e.addEventListener("click", (eve) => {
    let partClass = e.classList[0].split("-")[3];
    partClass == "7" ? filterThis("7") : false;
    partClass == "8" ? filterThis("8") : false;
    partClass == "9" ? filterThis("9") : false;
    partClass == "10" ? filterThis("10") : false;
    partClass == "math" ? filterThis("math") : false;
    partClass == "chemistry" ? filterThis("chemistry") : false;
    partClass == "biology" ? filterThis("biology") : false;
    partClass == "informatics" ? filterThis("informatics") : false;
    partClass == "physics" ? filterThis("physics") : false;
    partClass == "ruLang" ? filterThis("ruLang") : false;
  }),
    false;
});


// Это функция, которая принимает число или слова, в зависимости от нажатой кнопки.
const filterThis = (num) => {
//пробегаемся по всему массиву с li элементами
  filterLiCollection.forEach((e) => {
  //Делаем проверку, чтобы ниженаписанная логика относилась только к своим элементам (без этой проверки не робит)
    if (
      num == "math" ||
      num == "chemistry" ||
      num == "biology" ||
      num == "informatics" ||
      num == "physics" ||
      num == "ruLang"
    ) {
    //здесь фильтрация, которая отбирает те элементы, которые не являются нашей целью. Отбираются, чтобы их скрыть
      let ewq = filterLiCollection.filter(
        (filter) => filter.dataset.subject !== num
      );
      // Здесь удаляются display-none ТОЛЬКО с тех элементов, которые относятся непосредственно к выбору предмета. Это позволит нам выбрать класс, который сузит поиск до 5 элементов, потом выбрать предмет и перевыбирать его. Он будет перезаписываться. Без этого, уже после двух кликов по фильтрам лист окажется пустым.
      filterLiCollection.forEach((el) => el.classList.remove("subject-none"));
//Здесь мы получаем текст в споллере, чтобы менять его на текущий предмет
      let subjTitle = document.querySelector(".title-subject");
      num == "math" ? (subjTitle.innerHTML = `Математика`) : console.log("");
      num == "chemistry" ? (subjTitle.innerHTML = `Химия`) : console.log("");
      num == "biology" ? (subjTitle.innerHTML = `Биология`) : console.log("");
      num == "informatics"
        ? (subjTitle.innerHTML = `Информатика`)
        : console.log("");
      num == "physics" ? (subjTitle.innerHTML = `Физика`) : console.log("");
      num == "ruLang"
        ? (subjTitle.innerHTML = `Русский язык`)
        : console.log("");
     //Здесь мы добавляем класс, который будет скрывать те элементы, которые мы не выбирали.
      ewq.forEach((el) => el.classList.add("subject-none"));
      console.log(ewq);
    }
  });
  //Тут всё то же самое, что и в коде выше.
  if (num == "7" || num == "8" || num == "9" || num == "10") {
    filterLiCollection.forEach((el) => el.classList.remove("class-none"));
    let ewq = filterLiCollection.filter(
      (filter) => filter.dataset.class !== num
    );
    document.querySelector(".title-class").innerHTML = `${num} класс`;
    ewq.forEach((el) => el.classList.add("class-none"));
    console.log(ewq);
  }
};
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы