Home > Net >  Target multiple classes in a div and count number of times they have been clicked Vanilla JS
Target multiple classes in a div and count number of times they have been clicked Vanilla JS

Time:11-19

The purpose of this is to be able to track the number of times a button with class testButton or incButton has been clicked and if either has been clicked twice to show a overlay.

There are 2 main issues: 1: I'm not sure how to select 2 different classes of buttons 2: Once there are more than 1 button with the same class name the existing JS code does only works on the first button with the testButton class.

The code I have is:

<style>
    #winOverlay {
        position: fixed;
        z-index: 200;
        width: 100%;
        height: 100%;
        background-color: red;
        top: 0;
        left: 0;
    }
</style>

<div id="winOverlay" style="display:none"></div>

<div id="buttonContainer">
    <button class="testButton">1</button>
    <button class="incButton">2</button>
    <button class="testButton">3</button>
    <button class="incButton">4</button>
    <button class="testButton">5</button>
</div>


<script>
    var count = 0;
    var btn = document.getElementById("buttonContainer").querySelector(".testButton");

    btn.onclick = function () {
        count  ;
        if (count == 2) {
            document.getElementById('winOverlay').style.display = "block";
        }
    }
</script>

Any help would be greatly appreciated.

CodePudding user response:

You can make use of event Delegation where you add event listener on the common parent container with class buttonContainer and you can check if the button clicked with id only testButton and incButon

1) This code will work if you have to calculate of count of irrespective of which button is clicked.

var count = 0;
var btn = document.getElementById("buttonContainer");
const winOverlay = document.getElementById('winOverlay');

btn.addEventListener("click", e => {
  const classes = e.target.classList;
  if (classes.contains("testButton") || classes.contains("incButon")) {
    count  ;
    if (count === 2) winOverlay.style.display = "block";
  }
})
#winOverlay {
  position: fixed;
  z-index: 200;
  width: 100%;
  height: 100%;
  background-color: red;
  top: 0;
  left: 0;
}
<div id="winOverlay" style="display:none"></div>

<div id="buttonContainer">
  <button class="testButton">1</button>
  <button class="incButon">2</button>
  <button class="testButton">3</button>
  <button class="incButon">4</button>
  <button class="testButton">5</button>
</div>
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

2) This code will work if you have to calculate the count of specif key on which you clicked and show overlay if it's count is 2

var btn = document.getElementById("buttonContainer");
const winOverlay = document.getElementById("winOverlay");
const dict = {};

btn.addEventListener("click", (e) => {
  const classes = e.target.classList;
  const addOverlay = () => (winOverlay.style.display = "block");

  if (classes.contains("testButton") || classes.contains("incButon")) {
    const key = e.target.dataset.key;
    dict[key] = (dict[key] || 0)   1;
    if (dict[key] === 2) addOverlay();
  }
});
#winOverlay {
  position: fixed;
  z-index: 200;
  width: 100%;
  height: 100%;
  background-color: red;
  top: 0;
  left: 0;
}

button {
  color: white;
  border: none;
  padding: 1rem;
  cursor: pointer;
}

button.testButton {
  background-color: teal;
}

button.incButon {
  background-color: orange;
}
<div id="winOverlay" style="display: none;"></div>

<div id="buttonContainer">
  <button class="testButton" data-key="testButton">1</button>
  <button class="incButon" data-key="incButon">2</button>
  <button class="testButton" data-key="testButton">3</button>
  <button class="incButon" data-key="incButon">4</button>
  <button class="testButton" data-key="testButton">5</button>
</div>
<iframe name="sif2" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

CodePudding user response:

You need to select all buttons with querySelectorAll add listener to all of them.

var count = 0;
const buttons = document.querySelectorAll("#buttonContainer > button");
 
for (let index = 0; index < buttons.length; index  ) {
  const e = buttons[index];
  e.onclick = function() {
  count  ;
   if (count == 2) {
    document.getElementById('winOverlay').style.display = "block";
  }
}
}
#winOverlay {
  position: fixed;
  z-index: 200;
  width: 100%;
  height: 100%;
  background-color: red;
  top: 0;
  left: 0;
}
<div id="winOverlay" style="display:none"></div>

<div id="buttonContainer">
  <button class="testButton">1</button>
  <button class="incButon">2</button>
  <button class="testButton">3</button>
  <button class="incButon">4</button>
  <button class="testButton">5</button>
</div>
<iframe name="sif3" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

CodePudding user response:

To select 2 class you should do as in css:

querySelector(class1 class2)

But don't work because you can't use querySelector for two or more classes. This code say only select class1 or class2 and take the first Element.

Use querySelectorAll() to have all of them

CodePudding user response:

As the others have suggested querySelectorAll provides support for multiple selectors. It will return an array-like nodelist which you can then iterate over.

document.querySelectorAll('testButton', 'incButton');

I'm going to offer an alternative approach using event delegation which allows you to attach one listener to a parent element that captures events as they bubble up the DOM.

This example also uses a closure (basically a function that's returned from another function but that can carry any variables set outside it in the local lexical environment with it when it's returned. This is a useful pattern if you want to avoid global variables. In this case we create an object to hold the totals of the two types of buttons.

// Cache your container and overlay elements
const container = document.querySelector('.buttonContainer');
const overlay = document.querySelector('.overlay');

// Add one listener to the container which calls `handleClick`.
// `handleClick` sets up the object and returns a new function
// (the closure) that carries the object with it.
container.addEventListener('click', handleClick(), false);

function handleClick() {
  
  // An object that holds the button totals
  const cases = {
    testButton: 0,
    incButton: 0
  };
  
  // The function that will be added to the listener
  // It has the event argument
  return function (e) {

    // Destructure the nodeName/className from the
    // element that was clicked
    const { nodeName, className } = e.target;

    // Check to see if the element was a button
    if (nodeName === 'BUTTON') {

      // Increase the value in the object where
      // the key matches the className
        cases[className];
      console.log(JSON.stringify(cases));

      // If that value is 2 show the overlay
      if (cases[className] === 2) {
        overlay.classList.add('show');
      }

    }

  }

}
.overlay { display: none; margin: 1em; background-color: #acaccc; black: white; padding: 2em; }
.show { display: block; }
button { padding: 0.7em; }
button:hover { cursor: pointer; background-color: #acacac; }
<div class="buttonContainer">
  <button class="testButton">1</button>
  <button class="incButton">2</button>
  <button class="testButton">3</button>
  <button class="incButton">4</button>
  <button class="testButton">5</button>
</div>

<div class="overlay">Overlay</div>
<iframe name="sif4" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

Additional documentation

  • Related