2

I have a webpage with some divs displayed. There are some filters used on a webshop to filter specific items. Now I want to display the message "no results" if all divs have display:none.

How could I do that?

I tried some stuff like:

if ($('filters')(':visible').length == 0) {
  document.textContent('No results');
}

but that doesn't work.

const buttons = document.querySelectorAll('.btn');
const composers = document.querySelectorAll('.filterDiv');

buttons.forEach((btn) =>
  btn.addEventListener('click', (e) => {
    e.target.classList.toggle('active');
    filterSelection();
  }),
);

function filterSelection() {
  const filters = [...document.querySelectorAll('.btn.active')].map(
    (el) => el.dataset.filter,
  );
  composers.forEach(
    (c) =>
    (c.style.display =
      filters.length === 0 || c.matches(`.${filters.join('.')}`) ?
      'block' :
      'none'),
  );
}
<div id="filters">
  <div id="myBtnContainer">
    <p>Period</p>
    <button data-filter="Barok" class="btn">Barok</button>
    <button data-filter="Classic" class="btn">Classic</button>
    <button data-filter="Renaissance" class="btn">Renaissance</button>
    <button data-filter="Romantic" class="btn">Romantic</button>
  </div>
  <div id="myBtnContainer">
    <p>Composer</p>
    <button data-filter="DiLasso" class="btn">De Lassus</button>
    <button data-filter="Bach" class="btn">Bach</button>
    <button data-filter="Vivaldi" class="btn">Vivaldi</button>
    <button data-filter="Schubert" class="btn">Schubert</button>
    <button data-filter="Tchaikovsky" class="btn">Tchaikovsky</button>
  </div>
</div>
<div class="container" id="myUL">
  <div class="filterDiv Renaissance DiLasso">Di Lasso -Lagrime de San Pietro</div>
  <div class="filterDiv Renaissance">Sweelinck - Fantasie</div>
  <div class="filterDiv Classic">Haydn - The Seasons</div>
  <div class="filterDiv Romantic">Wagner - Parsifal</div>
  <div class="filterDiv Classic">Mozart - Requiem</div>
  <div class="filterDiv Barok Bach">Bach - Magnificat</div>
  <div class="filterDiv Classic">Beethoven - Symphony 5</div>
  <div class="filterDiv Barok">Händel - Hallelujah</div>
  <div class="filterDiv Barok Vivaldi">Vivaldi - The Four Seasons</div>
  <div class="filterDiv Renaissance">Obrecht - Factor Orbis</div>
  <div class="filterDiv Romantic Schubert">Schubert - Erlkönig</div>
  <div class="filterDiv Romantic Tchaikovsky">Tchaikovsky - Swan Lake</div>
  <div class="filterDiv Barok Vivaldi">Vivaldi - Rosmira</div>
  <div class="filterDiv Classic">Beethoven - Moonlight Sonata</div>
</div>
Roman Mahotskyi
  • 4,576
  • 5
  • 35
  • 68
  • Rather than alter the element style directly with `c.style.display = `block-or-none, it is better to add/remove/toggle classes like Nick Vu shows in his answer. It's also better to have the text already there but hidden as Nick shows. – Stephen P Nov 03 '22 at 17:00

2 Answers2

4

You can use a class to control your hidden elements by .filterDiv.hidden (if elements are hidden, they will have a class hidden).

This approach needs to have styles with CSS

.hidden {
   display: none;
}

const buttons = document.querySelectorAll('.btn');
const composers = document.querySelectorAll('.filterDiv');

buttons.forEach((btn) =>
  btn.addEventListener('click', (e) => {
    e.target.classList.toggle('active');
    filterSelection();
  }),
);

function filterSelection() {
  const filters = [...document.querySelectorAll('.btn.active')].map(
    (el) => el.dataset.filter,
  );
  composers.forEach((c) => {
    if (filters.length === 0 || c.matches(`.${filters.join('.')}`)) {
      c.classList.remove("hidden")
    } else {
      c.classList.add("hidden")
    }
  });

  const hiddenComposers = document.querySelectorAll('.filterDiv.hidden');

  const noResultElement = document.getElementById("noResult");

  if (composers.length === hiddenComposers.length) {
    noResultElement.classList.remove("hidden");
  } else {
    noResultElement.classList.add("hidden");
  }
}
.hidden {
  display: none;
}
<div id="filters">
  <div id="myBtnContainer">
    <p>Period</p>
    <button data-filter="Barok" class="btn">Barok</button>
    <button data-filter="Classic" class="btn">Classic</button>
    <button data-filter="Renaissance" class="btn">Renaissance</button>
    <button data-filter="Romantic" class="btn">Romantic</button>
  </div>
  <div id="myBtnContainer">
    <p>Composer</p>
    <button data-filter="DiLasso" class="btn">De Lassus</button>
    <button data-filter="Bach" class="btn">Bach</button>
    <button data-filter="Vivaldi" class="btn">Vivaldi</button>
    <button data-filter="Schubert" class="btn">Schubert</button>
    <button data-filter="Tchaikovsky" class="btn">Tchaikovsky</button>
  </div>
</div>
<div class="container" id="myUL">
  <div class="filterDiv Renaissance DiLasso">Di Lasso -Lagrime de San Pietro</div>
  <div class="filterDiv Renaissance">Sweelinck - Fantasie</div>
  <div class="filterDiv Classic">Haydn - The Seasons</div>
  <div class="filterDiv Romantic">Wagner - Parsifal</div>
  <div class="filterDiv Classic">Mozart - Requiem</div>
  <div class="filterDiv Barok Bach">Bach - Magnificat</div>
  <div class="filterDiv Classic">Beethoven - Symphony 5</div>
  <div class="filterDiv Barok">Händel - Hallelujah</div>
  <div class="filterDiv Barok Vivaldi">Vivaldi - The Four Seasons</div>
  <div class="filterDiv Renaissance">Obrecht - Factor Orbis</div>
  <div class="filterDiv Romantic Schubert">Schubert - Erlkönig</div>
  <div class="filterDiv Romantic Tchaikovsky">Tchaikovsky - Swan Lake</div>
  <div class="filterDiv Barok Vivaldi">Vivaldi - Rosmira</div>
  <div class="filterDiv Classic">Beethoven - Moonlight Sonata</div>
</div>
<div id="noResult" class="hidden">No result</div>
Nick Vu
  • 14,512
  • 4
  • 21
  • 31
1

All you need to do is to listen to a mutation of the document. then just do normal counting logic for those which are set to displaynone

const buttons = document.querySelectorAll('.btn');
const composers = document.querySelectorAll('.filterDiv');

buttons.forEach((btn) =>
  btn.addEventListener('click', (e) => {
    e.target.classList.toggle('active');
    filterSelection();
  }),
);

function filterSelection() {
  const filters = [...document.querySelectorAll('.btn.active')].map(
    (el) => el.dataset.filter,
  );
  composers.forEach(
    (c) =>
      (c.style.display =
        filters.length === 0 || c.matches(`.${filters.join('.')}`)
          ? 'block'
          : 'none'),
  );
}

MutationObserver = window.MutationObserver || window.WebKitMutationObserver;

var observer = new MutationObserver(function(mutations, observer) {
    // fired when a mutation occurs
        let filtersCount = [...$('.filterDiv')].length;
    let filtersNoneCount = [...$('.filterDiv')].filter((f,i) => {return f.style.display === "none"}).length;
    if(filtersCount === filtersNoneCount){
            $(document.body).html('No results');
    }
});

observer.observe(document, {
  subtree: true,
  attributes: true
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="filters">
  <div id="myBtnContainer">
    <p>Period</p>
    <button data-filter="Barok" class="btn">Barok</button>
    <button data-filter="Classic" class="btn">Classic</button>
    <button data-filter="Renaissance" class="btn">Renaissance</button>
    <button data-filter="Romantic" class="btn">Romantic</button>
  </div>
  <div id="myBtnContainer">
    <p>Composer</p>
    <button data-filter="DiLasso" class="btn">De Lassus</button>
    <button data-filter="Bach" class="btn">Bach</button>
    <button data-filter="Vivaldi" class="btn">Vivaldi</button>
    <button data-filter="Schubert" class="btn">Schubert</button>
    <button data-filter="Tchaikovsky" class="btn">Tchaikovsky</button>
  </div>
</div>
<div class="container" id="myUL">
  <div class="filterDiv Renaissance DiLasso">Di Lasso -Lagrime de San Pietro</div>
  <div class="filterDiv Renaissance">Sweelinck - Fantasie</div>
  <div class="filterDiv Classic">Haydn - The Seasons</div>
  <div class="filterDiv Romantic">Wagner - Parsifal</div>
  <div class="filterDiv Classic">Mozart - Requiem</div>
  <div class="filterDiv Barok Bach">Bach - Magnificat</div>
  <div class="filterDiv Classic">Beethoven - Symphony 5</div>
  <div class="filterDiv Barok">Händel - Hallelujah</div>
  <div class="filterDiv Barok Vivaldi">Vivaldi - The Four Seasons</div>
  <div class="filterDiv Renaissance">Obrecht - Factor Orbis</div>
  <div class="filterDiv Romantic Schubert">Schubert - Erlkönig</div>
  <div class="filterDiv Romantic Tchaikovsky">Tchaikovsky - Swan Lake</div>
  <div class="filterDiv Barok Vivaldi">Vivaldi - Rosmira</div>
  <div class="filterDiv Classic">Beethoven - Moonlight Sonata</div>
</div>

more docs

Dean Van Greunen
  • 5,060
  • 2
  • 14
  • 28