Select more than one class within a div and keep track of how many times they have been clicked using pure JavaScript

This code snippet serves the purpose of tracking the number of clicks on buttons with either the testButton or incButton class, and displaying an overlay after two clicks. However, two main issues have been identified: 1: Difficulty in selecting buttons with different classes. 2: The existing JavaScript code only works for the first button with the testButton class when there are multiple buttons with the same class name.

The provided code is as follows:

<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>

Your assistance in resolving these issues would be highly appreciated.

Answer №1

You can utilize the concept of event delegation by adding an event listener to the common parent container with the class buttonContainer. This way, you can determine if the button clicked has the id testButton or incButon.

1)

This code is designed to calculate the count 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>

2)

This code is meant for calculating the count based on the specific key of the button clicked and displaying the overlay when the count reaches 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>

Answer №2

To activate all buttons, use querySelectorAll to select them and add event listeners to each.

var counter = 0;
const buttonGroup = document.querySelectorAll("#buttonContainer > button");
 
for (let idx = 0; idx < buttonGroup.length; idx++) {
  const element = buttonGroup[idx];
  element.onclick = function() {
    counter++;
    if (counter == 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>

Answer №3

When choosing two classes in CSS, you need to follow these steps:

querySelector(class1 class2)

However, this method doesn't work because querySelector can only select one class at a time. It will only choose either class1 or class2 and grab the first Element it finds.

Instead, you should use querySelectorAll() to select all of them.

Answer №4

Like the suggestions from others, querySelectorAll allows for multiple selectors. It returns an array-like nodelist that can be iterated over.

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

An alternative method is through event delegation, which enables attaching one listener to a parent element to capture events as they bubble up the DOM.

This example features a closure, creating a function within another function that retains variables set outside it in the local lexical environment when returned. This eliminates the need for global variables by using an object to store button totals.

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

container.addEventListener('click', handleClick(), false);

function handleClick() {
  
  const cases = {
    testButton: 0,
    incButton: 0
  };
  
  return function (e) {

    const { nodeName, className } = e.target;

    if (nodeName === 'BUTTON') {
      
      ++cases[className];
      console.log(JSON.stringify(cases));

      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>

Additional resources:

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Excessive API requests can occur when Redux dispatches an action multiple times

Utilizing the Jikan API for anime, my objective is to showcase promo thumbnails of new anime shows. This involves two separate API calls: one to retrieve the latest anime shows: export const get_new_anime = () => `${base_url}search/anime?q&order_b ...

Sluggishness in updating properties in a child component using React

Within my main component, I have a button that captures the details of the chosen item and displays them in input fields within a subordinate component. The primary component showcases, <h4 className="table-title">Status</h4> <div classNam ...

Even after being removed from the DOM using Ajax load, JQuery continues to execute

Currently, within my Laravel 5.2 single page application development, I am faced with the following issue. I have an add.blade.php file and an edit.blade.php file, both containing a script with the same class name and id. When I use .load to load add.blade ...

KnockoutJS is not recognizing containerless if binding functionality

I was recently faced with the task of displaying a specific property only if it is defined. If the property is not defined, I needed to show a DIV element containing some instructions. Despite my efforts using $root and the bind property, I couldn't ...

Troubleshooting HTTP requests in Angular JS when dealing with nested scopes

This particular question is derived from a previous answer found at this link. In my current scenario, I am attempting to initiate an http request where one of the data values that needs to be sent is represented in the view as {{selectedCountry.shippin ...

The function vue.findIndex is not recognized as a valid function

Encountered an issue with the findIndex() function Uncaught (in promise) TypeError: state.carts.findIndex is not a function The cartId includes rowId, qty, sizeVal, and image Methods updateCart() { this.$store.dispatch('updateCart&apos ...

Develop a technique to transfer properties to elements in a REACT environment

Is there a way to create a function that passes props to multiple components? passingPropsMethod(){ return( something={this.state.something} something2={this.state.something2} ) } I attempted this code, but it showed "Unreachable co ...

Looping through an array asynchronously and returning the result

I'm having some trouble with an asynchronous loop. Here's the code I've been working with: let items = []; data.forEach(async item => { var newItem = new Item(data); newItem.options = await this.fetchOptions(data[" ...

Interact with a JSON API using JavaScript by incorporating dynamic user input

Recently, I delved into tutorials on utilizing JSON data and JavaScript. Feeling inspired, I decided to create a simple app using an API. However, I encountered a hurdle and I'm struggling to identify its cause. The problem seems to be related to how ...

Scrolling function for an automatically adjusting menu bar

I need help creating a dynamic menu that automatically adjusts in size as the user scrolls down. I found a script online and added it to my HTML file like this: <script type="text/javascript"> $(function() { var header = $(".large"); $(windo ...

Having trouble making the swing effect trigger on mouseover but not on page load

I am trying to achieve a swinging effect on mouseover only, not on page load. Below is the JS code I have: (function swing() { var ang = 20, dAng = 10, ddAng = .5, dir = 1, box = document.getElementById("box"); (function setAng(ang){ ...

I am interested in developing a select box with autocomplete functionality

Here is the HTML code I have: <select class="form-control" id="city" style="width:100%; margin-left:2%;"> <option>Sonal</option> <option>abcd</option> <option>3</option> <option& ...

Exploring variable comparisons in Javascript

I am currently working on a script that captures the input values of image tags when clicked and I need to compare them to see if they match. Since I am still in the process of learning JavaScript and JQuery, I could really use some assistance. Below is my ...

Properly defining the selector for the element.closest() method in the DOM

How can I access the ID of the outermost div from the inner button element in this HTML snippet? <div id="menu_level_0" class="menu_level"> <div class="editor"> <div class="ui_detail ...

Color picker can be utilized as an HTML input element by following these steps

After trying out various color pickers, I was not satisfied with their performance until I stumbled upon Spectrum - The No Hassle jQuery Colorpicker. It perfectly met my requirements. <html> <head> <meta http-equiv="content-type" content="t ...

Working with JSON structure using Javascript

I successfully transformed an XML file into a JSON format, but now I need to manipulate the data in order to achieve a specific desired structure. Here is the Original format { "machine": "Hassia2", "actual_product_date": "08/24/2017", "holdi ...

Maximizing Jest's potential with multiple presets in a single configuration file/setup

Currently, the project I am working on has Jest configured and testing is functioning correctly. Here is a glimpse of the existing jest.config.js file; const ignores = [...]; const coverageIgnores = [...]; module.exports = { roots: ['<rootDir&g ...

Struggling to transmit data to material dialog in Angular2+

I am facing an issue with my Material Dialog not working properly. Can anyone point out what I might be missing? product-thumbnail.ts I will use this to trigger the dialog export class ProductThumbnailComponent implements OnInit { @Input() product: Pr ...

Synchronize two div elements with JavaScript

The demonstration features two parent divs, each containing a child div! The first parent div's child div is draggable and resizable using JQueryUI. There are events for both dragEnd and resizeEnd associated with this div. The goal is to synchronize ...

Managing integer values in controllers with .NET Core 6

I have a simple API controller where I can manipulate any model in my design, but I'm having trouble handling int or string values. Here's a snippet of my code: [Route("Get"), HttpPost] public async Task<JResultModel> Get(int id) { if ...