0

I have a list of cards, when you click on a card, it opens and a class "opened" is added to it. How to make it so that when all the cards are opened a button will appear (does not matter the button or some other action);

HTML when the program starts:

<ul id='container'>
    <li class='card'></li>
    <li class='card'></li>
    <li class='card'></li>
    <li class='card'></li>
    <li class='card'></li>
</ul>

When all cards opened:

<ul id='container'>
    <li class='card opened'></li>
    <li class='card opened'></li>
    <li class='card opened'></li>
    <li class='card opened'></li>
    <li class='card opened'></li>
</ul>
<button class='btn-restart'>Restart</button>

EDITED:

for some reason, even when i make the button appear when at least 1 card has a class 'opened', nothing happens

JS:

function couplesApp() {
    const container = document.getElementById('container');
    const buttonRestart = createRestartButton();

    // some other essential stuff i didn't include

    const cards = document.getElementsByClassName('card');
    for (let i = 0; i < cards.length; i++) {
        if (cards[i].classList.contains('opened')) {
            container.append(buttonRestart);
        };
    };

EDITED (2):

SOLUTION IS:

document.querySelector('#container').addEventListener('click', () => {
        const cards = document.getElementsByClassName('card');
        for (let i = 0; i < cards.length; i++) {
            if (cards.length === document.querySelectorAll('.card.opened').length){
                container.append(buttonRestart);
            };  
        };
    });

Thanks to Scott Marcus.

  • 2
    You could use `if(document.querySelector('#container .card:not(.opened)') === null){...all cards are opened...}` to check whether all `.card` inside `#container` are also `.opened`. – Lain Oct 26 '22 at 13:20

3 Answers3

1

See comments inline below:

// Get reference to all the li.card elements and the hidden button
let cards = document.querySelectorAll("#container > li.card");
const button = document.querySelector(".btn-restart");

// Set up an event handler on the card container
document.querySelector("#container").addEventListener("click", function(event){
  // Check to see if the click event originated at a LI element
  if(event.target.nodeName === "LI"){
    // Add the opened class to the clicked LI
    event.target.classList.add("opened");
    
    // If the amount of cards matches the amount of opened cards...
    if(cards.length === document.querySelectorAll(".card.opened").length){
      button.classList.remove("hidden");  // Unhide the button
    }
  }
});
.hidden { display:none; }
<ul id='container'>
    <li class='card'>1</li>
    <li class='card'>2</li>
    <li class='card'>3</li>
    <li class='card'>4</li>
    <li class='card'>5</li>
</ul>
<button class='btn-restart hidden'>Restart</button>
Scott Marcus
  • 64,069
  • 6
  • 49
  • 71
0

If you always know the amount of cards beforehand, you can check if the number of elements with the class opened matches the number of cards:

if (document.getElementsByClassName("opened").length === 5) { }

If you do not know the number of cards then use the same document.getElementsByClassName to get all elements with the class card and iteratively check if all of them have the class opened.

let allOpened = true;
const cards = document.getElementsByClassName("card");
for (let i = 0; i < cards.length; i++) {
    if (!cards[i].classList.contains("opened")) {
        allOpened = false;
    }
}
  • Just beware that you should not use the class 'card' for anything else in your application. If you do have the class card used on other places, consider using another selector than the whole document. You could also just count the length of cards constant and see if it matches the length of ````document.getElementsByClassName("opened");``` That's going to save you the trouble of going through a for-loop every time. – Clueless_captain Oct 26 '22 at 13:34
  • @Clueless_captain There is nothing wrong with using the same class name in other places in the document as long as your selector qualifies the correct set of elements (see my answer below). And by using [event delegation](https://javascript.info/event-delegation) (again, see my answer below), you avoid a loop and multiple event handlers. Also, [don't use `getElementsByClassName()`](https://stackoverflow.com/questions/54952088/how-to-modify-style-to-html-elements-styled-externally-with-css-using-js/54952474#54952474). – Scott Marcus Oct 26 '22 at 13:36
  • Pedro, these 2 methods are what immediately came to my mind when I tried to do it myself, for some reason nothing happens after I have selected all the cards – hasanBigBaboon Oct 26 '22 at 13:56
0

Using js you can check all the items with class card inside container if they have class opened or not:

[...document.querySelectorAll('.container .card')]
    .every(item => item.classList.contains('opened')) 
Fettah_Aud
  • 21
  • 3