skip to Main Content

I want to filter and display list items in an HTML based on specific criteria when clicking buttons. The list items have "circle" and "checked" classes. I’ve created buttons to show all, active, or achieved items.

I managed to filter the list but I’m having trouble displaying each item correctly

const parent = document.querySelector('.circle-parent'),
  filter = document.querySelector('.filters'),
  items = document.querySelectorAll('.circle');

filter.addEventListener('click', elem => {
  elem = elem.target;
  if (elem.id === "all") {
    parent.innerHTML = Array.from(items);
  } else if (elem.id === "active") {
    parent.innerHTML = Array.from(items).filter(e => e.className.includes('checked'));
  } else {
    parent.innerHTML = Array.from(items).filter(e => !e.className.includes('checked'));
  }
})
.checked {
  color: red;
}
<ul class="circle-parent">
  <li class="circle">circle</li>
  <li class="circle">circle</li>
  <li class="circle checked">circle</li>
</ul>

<div class="filters">
  <button id="all">all</button>
  <button id="active">active</button>
  <button id="achieved">achieved</button>
</div>

2

Answers


  1. Instead of setting the parent’s HTML (parent.innerHTML = ..), you can change the styling of the elements to show/hide them.

    Here is an example:

    const parent = document.querySelector('.circle-parent'),
      filter = document.querySelector('.filters'),
      items = document.querySelectorAll('.circle');
    
    filter.addEventListener('click', elem => {
      elem = elem.target;
      if (elem.id === "all") {
        Array.from(items).forEach((e) => {
          e.style.display = 'list-item';
        });
      } else if (elem.id === "active") {
        Array.from(items).forEach((e) => {
          e.style.display = e.className.includes('checked') ? 'list-item' : 'none';
        });
      } else {
        Array.from(items).forEach((e) => {
          e.style.display = !e.className.includes('checked') ? 'list-item' : 'none';
        });
      }
    })
    .checked {
      color: red;
    }
    <ul class="circle-parent">
      <li class="circle">circle</li>
      <li class="circle">circle</li>
      <li class="circle checked">circle</li>
    </ul>
    
    <div class="filters">
      <button id="all">all</button>
      <button id="active">active</button>
      <button id="achieved">achieved</button>
    </div>

    This solution is specific to your example because I’ve used the CSS display property list-item which is the default for li elements.

    A more general solution will be to define in CSS the styling of a class as display: none and add/remove that class from elements to show/hide them.

    This is a more general solution:

    const parent = document.querySelector('.circle-parent'),
      filter = document.querySelector('.filters'),
      items = document.querySelectorAll('.circle');
    
    filter.addEventListener('click', elem => {
      elem = elem.target;
      if (elem.id === "all") {
        Array.from(items).forEach((e) => {
          e.classList.remove('hidden');
        });
      } else if (elem.id === "active") {
        Array.from(items).forEach((e) => {
          if (e.className.includes('checked')) {
            e.classList.remove('hidden');
          } else {
            e.classList.add('hidden');
          }
        });
      } else {
        Array.from(items).forEach((e) => {
          if (!e.className.includes('checked')) {
            e.classList.remove('hidden');
          } else {
            e.classList.add('hidden');
          }
        });
      }
    })
    .checked {
      color: red;
    }
    
    .hidden {
      display: none;
    }
    <ul class="circle-parent">
      <li class="circle">circle</li>
      <li class="circle">circle</li>
      <li class="circle checked">circle</li>
    </ul>
    
    <div class="filters">
      <button id="all">all</button>
      <button id="active">active</button>
      <button id="achieved">achieved</button>
    </div>
    Login or Signup to reply.
  2. Here is a DRY version using the other answer as basis

    const parent = document.querySelector('.circle-parent');
    const filter = document.querySelector('.filters');
    const items = document.querySelectorAll('.circle');
    
    filter.addEventListener('click', (event) => {
      const item = event.target.closest('button'); // button can have children
      const showAll = item.id === 'all';
      const showActive = item.id === 'active';
      items.forEach((circle) => {
        const isChecked = circle.matches('.checked');
        circle.classList.toggle('hidden', !showAll && (showActive ? !isChecked : isChecked));
      });
    });
    .checked {
      color: red;
    }
    
    .hidden {
      display: none;
    }
    <ul class="circle-parent">
      <li class="circle">circle</li>
      <li class="circle">circle</li>
      <li class="circle checked">circle</li>
    </ul>
    
    <div class="filters">
      <button id="all">all</button>
      <button id="active">active</button>
      <button id="achieved">achieved</button>
    </div>

    Shorter code using hidden attribute

    circle.hidden = !showAll && (showActive ? !isChecked : isChecked);
    
    const parent = document.querySelector('.circle-parent');
    const filter = document.querySelector('.filters');
    const items = document.querySelectorAll('.circle');
    
    filter.addEventListener('click', (event) => {
      const item = event.target.closest('button'); // button can have children
      const showAll = item.id === 'all';
      const showActive = item.id === 'active';
      items.forEach((circle) => {
        const isChecked = circle.matches('.checked');
        circle.hidden = !showAll && (showActive ? !isChecked : isChecked);
      });
    });
    .checked {
      color: red;
    }
    <ul class="circle-parent">
      <li class="circle">circle</li>
      <li class="circle">circle</li>
      <li class="circle checked">circle</li>
    </ul>
    
    <div class="filters">
      <button id="all">all</button>
      <button id="active">active</button>
      <button id="achieved">achieved</button>
    </div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search