1

I am implementing a game of set using javascript. I have a class to discern whether or not the card is being selected and I will add the class to this when this method is called, which is when the card is clicked as there is an eventListener for it. However, the issue I have is implementing a deselect eventListener to be able to click so the selected class is gone but be able to click again and the selected class is back and behaves as it would have earlier. Here is the code for the function that runs when you select the card:

function cardSelected() {
  let setCount = qs('#set-count');
  let board = qs('#board');
  this.classList.add('selected');
  let selected = qsa('#board .selected');
  let count = selected.length;
  if (count === 3 && isASet(selected)) {
    for (let i = 0; i < selected.length; i++) {
      let card = generateUniqueCard(true);
      board.replaceChild(card, selected[i]);
      selected[i].classList.remove('selected');
      let paragraph = createParagraph('SET!');
      let timer = setTimeout((i) => {
        card.classList.add('hide-imgs');
        card.appendChild(paragraph);
      }, 0);
      setTimeout(() => {
        clearTimeout(timer);
        card.classList.remove('hide-imgs');
        card.removeChild(paragraph);
      }, 1000);
    }
    setCount.textContent = parseFloat(setCount.textContent) + 1;
  } else if (count === 3 && !isASet(selected)) {
    for (let i = 0; i < selected.length; i++) {
      selected[i].classList.remove('selected');
      let paragraph = createParagraph('Not a Set');
      let card = generateUniqueCard(true);
      board.replaceChild(card, selected[i]);
      let timer = setTimeout((i) => {
        card.classList.add('hide-imgs');
        card.appendChild(paragraph);
      }, 0);
      setTimeout((i) => {
        clearTimeout(timer);
        card.classList.remove('hide-imgs');
        card.removeChild(paragraph);
      }, 1000);
    }
  }
}
Alexander Nied
  • 12,804
  • 4
  • 25
  • 45
Luqman
  • 21
  • 8
  • 2
    you should just have a single click handler that will check if there's the class that marks the element as selected. Based on that condition you'll implement the toggling logic that sets/unsets to respectively select/unselect the item in your domain – Diego D Apr 26 '22 at 14:55
  • 3
    [element.classList.toggle](https://developer.mozilla.org/en-US/docs/Web/API/Element/classList) – Yogi Apr 26 '22 at 14:55
  • 1
    And that code is a big mess... it would be much easier to just add a single generic function as click handler to the elements matching a given selectors.. and such function will deal with event.target to make its considerations specific to the single case – Diego D Apr 26 '22 at 14:57
  • 1
    A few tips: If you kept references to the HTML elements instead of reselecting them every time you call the handler, the code inside your event handler would be smaller and easier to wrap your head around. You could also maintain the state of the game independently from the HTML elements, dividing the program into smaller problems. – Domino Apr 26 '22 at 15:03
  • Thank you all so much! It really was as simple as toggling :,) I do agree with all your points for fixing my code, I'll fix that right now! – Luqman Apr 26 '22 at 15:10

1 Answers1

0

Here is a working snippet that shows how you could do it with .classList.toggle("selected"):

const cont=document.querySelector("div.cont")

// build a sample deck of cards:
cont.innerHTML=[...Array(16)].map((_,i)=>`<span>card ${i+1}</span>`).join(" ");

// selection
cont.onclick=ev=>{
 if(ev.target.tagName==="SPAN") ev.target.classList.toggle("selected");
}
.cont span {display:inline-block; border: 1px solid grey; 
            padding:8px; margin:4px; background-color: #eee}
span.selected {background-color: red}
<div class="cont"></div>
Carsten Massmann
  • 26,510
  • 2
  • 22
  • 43