I have a list of several elements, and some controlling buttons that can hide/show these elements. Some buttons have control over just one element, while others have multiple elements.

What does my code do:

  • Button01 hides/shows ElementX and ElementY,
  • Button02 hides/shows only ElementY.
  • Once Button01 is clicked, both of the elements are hidden, and clicking Button02 doesn’t change anything until Button01 is clicked again.

What I want to do:

  • Once Button01 hides ElementX and ElementY, Button02 must also be grayed out automatically because its associated element is gone.
  • And then, clicking Button02 should bring ElementY back and enable Button01 too since one of the associated elements of Button01 is back.
for (let button of document.querySelectorAll(".filterbutton")) {
    button.addEventListener("click", filter);
}

let filters = new Set;

function toggleDisplay(selector, display) {
    let elems = document.querySelectorAll(selector);
    for (let elem of elems) {
        elem.style.display = display;
    }
}

function filter() {
    let filterSelector = this.dataset.filter;
    let show = filters.delete(filterSelector);
    this.style.color = show ? "" : "rgb(200,200,200)";
    if (!show) {
        filters.add(filterSelector); // toggle this filter
    } else {
        toggleDisplay(filterSelector, "");
    }
    if (filters.size) {
        toggleDisplay([...filters].join(","), "none");
    }
}
<div class="filterbutton" data-filter=".filter01">Filter01</div>
<div class="filterbutton" data-filter=".filter02">Filter02</div>

<div class="filter01">ElementX</div>
<div class="filter01 filter02">ElementY</div>

3

You would need to compare the shown elements with the filters on each button when a button gets clicked. See the solution below

const btns = Array.from( document.getElementsByClassName( 'filterbutton' ) );
const els = Array.from( document.getElementsByClassName( 'element' ) );

document.addEventListener( 'click', function( event ) {
  const target = event.target.parentElement;

  if ( target.hasAttribute('data-filter') ) {

    const filter = target.getAttribute( 'data-filter' ).split(" ");

    /* If button is active remove matching elements else show */
    !target.classList.contains( 'hide' )
      ? filter.forEach( el => els[el - 1].classList.add( 'hide' ) )
      : filter.forEach( el => els[el - 1].classList.remove( 'hide' ) );

    btns.forEach( btn => {
      const filter = btn.getAttribute( 'data-filter' ).split(" ");
      
      /* Empty array to push true/false if buttons matching elements are visible */
      const matches = [];
      filter.forEach( match => matches.push( els[match - 1].classList.contains( 'hide' ) ) );
      
      /* If any matches are visible button is active */
      matches.includes( false )
        ? btn.classList.remove( 'hide' )
        : btn.classList.add( 'hide' );
    });
  }
});
* { box-sizing: border-box } body { font-family: monospace; margin: 0 } hr { margin: 1em 0 }

:root { --transTime: .25s; --transFunction: ease-in-out }

#filters, #elements { display: flex; gap: 1em }

.filterbutton, .element {
  --trans: opacity var(--transTime) var(--transFunction);
  transition: var(--trans); -o-transition: width var(--trans); -moz-transition: var(--trans); -webkit-transition: var(--trans);
}

.filterbutton {
  border: 1px solid currentColor;
  border-radius: .375em;
  color: black;
  font-family: inherit;
  padding: .5em 1em;
  position: relative;
}
.filterbutton.hide { opacity: .5 }

.filterbutton span::before {
  border-radius: .375em;
  content: "";
  cursor: pointer;
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;
  z-index: 1;
}

.filterbutton span:first-of-type { display: inline }
.filterbutton span:last-of-type { display: none }

.filterbutton.hide span:first-of-type { display: none }
.filterbutton.hide span:last-of-type { display: inline }

.element {
  background: lightgrey;
  flex: 1 0 0%;
  padding: 1em;
  text-align: center;
}
.element.hide { opacity: 0 }
<div id="filters">
  <button class="filterbutton" type="button" data-filter="1 2 3 4">
    <span>Hide</span><span>Show</span> All
  </button>
  <button class="filterbutton" type="button" data-filter="1">
    <span>Hide</span><span>Show</span> 1
  </button>
  <button class="filterbutton" type="button" data-filter="2 3">
    <span>Hide</span><span>Show</span> 2 & 3
  </button>
  <button class="filterbutton" type="button" data-filter="4">
    <span>Hide</span><span>Show</span> 4
  </button>
</div>

<hr>

<div id="elements">
  <article class="element">Element 1</article>
  <article class="element">Element 2</article>
  <article class="element">Element 3</article>
  <article class="element">Element 4</article>
</div>

3

Since you have not given a specific problem that can be expressed by code, the answer can only be given algorithmically:

Аdd class active to the visible elements. after clicking the filter button, remove this class from the filtered elements. at the end of filtering, go through all the buttons and if the result is document.querySelectorAll(‘.active.filter’) empty set – disabled the filter button.