The optimal method for selecting a button from a group of buttons on a calculator using pure JavaScript

I have developed an HTML/CSS code inspired by the Mac/Apple calculator design. It features buttons organized in 5 rows using flexbox.

You can view my code on this codepen:

<div class="wrapper">
  <div class="calheader">
      <h2>Simple Calculator</h2>
    </div>
  <div class="calculatorbox">
    <div class="calwindow">
      <!-- ENTRY BOX -->
     <div class="entry">
        <p id="answer"></p>
      </div>
      <div class="entryhistory">
        <p id="history"></p>
      </div>
    </div>
    <!-- BUTTONS \\-->
    <div class="calbuttons">
      <div class="row">
        <button id="clear" class="key topcolor" value="clear">C</button>
        <button class="key topcolor" value="plusminus"><sup>+</sup>/<sub>−</sub></button>
        <button class="key topcolor" value="%">%</button>
        <button id="divide" class="key orange" value="/">÷</button>
      </div>
      <div class="row">
        <button id="seven" class="key" value="7">7</button>
        <button id="eight" class="key" value="8">8</button>
        <button id="nine" class="key" value="9">9</button>
        <button id="multiply" class="key orange" value="*">×</button>
      </div>
      <div class="row">
        <button id="four" class="key" value="4">4</button>
        <button id="five" class="key" value="5">5</button>
        <button id="six" class="key" value="6">6</button>
        <button id="subtract" class="key orange" value="-">−</button>
      </div>
      <div class="row">
        <button id="one" class="key" value="1">1</button>
        <button id="two" class="key" value="2">2</button>
        <button id="three" class="key" value="3">3</button>
        <button id="add" class="key orange" value="+">+</button>
      </div>
      <div class="row">
        <button id="zero" class="key btnspan" value="0">0</button>
        <button id="decimal" class="key" value=".">.</button>
        <button id="equals" class="key orange" value="=">=</button>
      </div>
    </div>
  </div>
</div>

Currently, I am exploring how to individually select and apply the addEventListener function to each button element.

A different JavaScript tutorial I came across utilizes a simpler structure as shown below:

<div class="calculator-keys">
    
    <button type="button" class="operator" value="+">+</button>
    <button type="button" class="operator" value="-">-</button>
    <button type="button" class="operator" value="*">&times;</button>
    <button type="button" class="operator" value="/">&divide;</button>

    <button type="button" value="7">7</button>
    <button type="button" value="8">8</button>
    <button type="button" value="9">9</button>


    <button type="button" value="4">4</button>
    <button type="button" value="5">5</button>
    <button type="button" value="6">6</button>


    <button type="button" value="1">1</button>
    <button type="button" value="2">2</button>
    <button type="button" value="3">3</button>


    <button type="button" value="0">0</button>
    <button type="button" class="decimal" value=".">.</button>
    <button type="button" class="all-clear" value="all-clear">AC</button>

    <button type="button" class="equal-sign operator" value="=">=</button>

  </div>

The tutorial goes on to illustrate how to interact with these elements using JavaScript:

const keys = document.querySelector('.calculator-keys');

keys.addEventListener('click', (event) => {
  const { target } = event;
  console.log('digit', target.value);
});

In this context, the querySelector method is utilized to target all children within the calculator-keys class for interaction.

In my situation, I was able to implement this functionality only for the first row of buttons. If I proceed to use querySelectorAll, would it be necessary to employ .map(), .forEach(), or some other technique to effectively utilize addEventListener for each individual button?

Answer №1

querySelector only retrieves one element at a time, so you should utilize querySelectorAll instead. To accomplish this, you need to target all elements with the class key and then attach an event listener for each key.

 const keys = document.querySelectorAll('.key');

keys.forEach(item => {
 item.addEventListener('click', (event) => {
    const { target } = event;
    console.log('digit', target.value);
    });
});
<div class="wrapper">
  <div class="calheader">
      <h2>Simple Calculator</h2>
    </div>
  <div class="calculatorbox">
    <div class="calwindow">
      <!-- ENTRY BOX -->
     <div class="entry">
        <p id="answer"></p>
      </div>
      <div class="entryhistory">
        <p id="history"></p>
      </div>
    </div>
    <!-- BUTTONS \\-->
    <div class="calbuttons">
      <div class="row">
        <button id="clear" class="key topcolor" value="clear">C</button>
        <button class="key topcolor" value="plusminus"><sup>+</sup>/<sub>−</sub></button>
        <button class="key topcolor" value="%">%</button>
        <button id="divide" class="key orange" value="/">÷</button>
      </div>
      <div class="row">
        <button id="seven" class="key" value="7">7</button>
        <button id="eight" class="key" value="8">8</button>
        <button id="nine" class="key" value="9">9</button>
        <button id="multiply" class="key orange" value="*">×</button>
      </div>
      <div class="row">
        <button id="four" class="key" value="4">4</button>
        <button id="five" class="key" value="5">5</button>
        <button id="six" class="key" value="6">6</button>
        <button id="subtract" class="key orange" value="-">−</button>
      </div>
      <div class="row">
        <button id="one" class="key" value="1">1</button>
        <button id="two" class="key" value="2">2</button>
        <button id="three" class="key" value="3">3</button>
        <button id="add" class="key orange" value="+">+</button>
      </div>
      <div class="row">
        <button id="zero" class="key btnspan" value="0">0</button>
        <button id="decimal" class="key" value=".">.</button>
        <button id="equals" class="key orange" value="=">=</button>
      </div>
    </div>
  </div>
</div>

Answer №2

Event delegation in the DOM refers to handling events that bubble up from multiple elements. This approach simplifies code, particularly when adding or removing elements, and also helps conserve memory.

Here are some examples of event delegation:

  1. JavaScript Event Delegation

  2. DOM Events

If you're using Javascript and have a list of buttons with the class 'key', you can utilize the following code snippet to attach an EventListener to each button.

let buttons = document.getElementsByClassName('key');
for(let i = 0; i<buttons.length; i++){
   buttons[i].addEventListener('click', () => {
      /*add your code here*/
   });
}

Answer №3

To convert a NodeList to an array using querySelectoAll, you can iterate through the buttons and add an eventListener.

let buttons = document.querySelectorAll('.btn');
let arrButtons = Array.from(buttons);

console.log(arrButtons)

for(button of arrButtons){
  button.addEventListener('click', () => {
    console.log('event');
  })
}
<button class="btn">Go!</button>
<button class="btn">Go!</button>
<button class="btn">Go!</button>
<button class="btn">Go!</button>

Answer №4

A highly recommended approach is to utilize event delegation. By doing so, you avoid the need to individually attach event listeners to each button and instead only attach it to their parent container.

const calcKeys = document.querySelector(".calculator-keys");

// Event listener only added to the parent container
calcKeys.addEventListener("click", (event) => {

  // Ignoring clicks from non-button elements
  if (event.target.nodeName !== "BUTTON") return;

  console.log(event.target.value);
});
<div class="calculator-keys">
  <button type="button" class="operator" value="+">+</button>
  <button type="button" class="operator" value="-">-</button>
  <button type="button" class="operator" value="*">&times;</button>
  <button type="button" class="operator" value="/">&divide;</button>

  <button type="button" value="7">7</button>
  <button type="button" value="8">8</button>
  <button type="button" value="9">9</button>

  <button type="button" value="4">4</button>
  <button type="button" value="5">5</button>
  <button type="button" value="6">6</button>

  <button type="button" value="1">1</button>
  <button type="button" value="2">2</button>
  <button type="button" value="3">3</button>

  <button type="button" value="0">0</button>
  <button type="button" class="decimal" value=".">.</button>
  <button type="button" class="all-clear" value="AC">AC</button>

  <button type="button" class="equal-sign operator" value="=">=</button>
</div>

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

Create a feature in three.js that allows users to click on an object to display information about the

After loading an object using the GLTF loader into my scene, I want to create a point on this object to display popup info. Is there a way to add a point to a specific location on the object? ...

What is the best way to design a page with a fixed dimension element and a flexible liquid element?

Is there a way to achieve the layout described below without relying on tables? Left element (100px) | Right element (occupies remaining space, even with no content) Thank you! Edit: Here's the link to the code: http://pastebin.com/vU33jNxD ...

Calculating the number of digits in a series of numbers, experiencing a timeout issue (What is the page count of a book? from codewars)

Solving the Digits in a Book Problem Find the number of pages in a book based on its summary. For example, if the input summary is 25, then the output should be n=17. This means that the numbers 1 to 17 have a total of 25 digits: 123456789101112131415161 ...

Python script utilizing Selenium is returning an empty string when trying to extract data from

When I try to retrieve the value from a dynamically loading table by clicking on the TD element, it works fine. However, when I attempt to fetch the text from the same TD element, it returns an empty string despite trying XPATH and CSS Selector methods. H ...

Combining Repetitive Elements in an Array

Trying to combine an array of products with the same order_id while also including all objects from a second products array. Below are some sample orders: const orders = [ { "order_details": { }, "order_id": "1", ...

Issue with the statement not being recognized for counting the space bar

I created a counter but I'm having trouble incorporating if statements For example: if (hits == 1) {alert("hello world1")} if (hits == 2) {alert("hello world2")} if (hits == 3) {alert("hello world3")} if (hits == 4) {alert("hello world4")} This is t ...

Utilize jQuery to animate the hiding of my right sidebar

Looking for help with implementing a jQuery animation to hide the right sidebar on my 3-columns page. I created a demo online here - JsFiddle: http://jsfiddle.net/yhfXX/ In my template, the columns are arranged as follows: menu (on the left) is fixed co ...

Is it possible to switch the background-image after a gif has finished loading?

I am currently using a GIF as a background image, but I would like it to show a static image until the GIF is fully loaded and ready to play. After reading several similar discussions, I understand that you can manipulate elements with JavaScript once the ...

Is the state of the React.js component empty?

HTML: <!-- index.html --> <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>React Tutorial</title> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.6/react.js"></script> ...

The state of XMLHttpRequest always remains in a perpetual state of progress, never

I have come across an MVC Core application. One of the methods in this application currently has the following structure: public IActionResult Call(string call) { Response.ContentType = "text/plain"; return Ok(call); } In addi ...

Angular utilizes array format to store data in the $scope

I am working on an Angular test application where I am trying to retrieve data from a PHP page into my model. The response comes using the echo json_encode($arr); command in the PHP file and has the format [{"id":"1","name":"first","text":"description"}]. ...

Not all API results are being displayed by the Nextjs API function

I am facing an issue with rendering all the returns from the API in my Next.js application. The API, which is created in Strapi, is only displaying 1 out of the 3 possible returns. I am a beginner when it comes to using APIs and I suspect that the issue li ...

Ways to locate two div class elements that are generated dynamically

I am looking to dynamically create 2 divs in different locations. One for displaying information and another for editing information. I want to be able to delete both divs with the same class when using the delete button. Since they are located in differe ...

Playing out the REST endpoint in ExpressJS simulation

Suppose I have set up the following endpoints in my ExpressJS configuration file server.js: // Generic app.post('/mycontext/:_version/:_controller/:_file', (req, res) => { const {_version,_controller,_file} = req.params; const ...

The HTML embed element is utilized to display multimedia content within a webpage, encompassing

Currently, I am working on a static website for my Computer Networks course. Students need to be able to download homework files in PDF format from the website. I have used embed tags to display the files online, but I'm facing an issue where the embe ...

retrieve the value obtained from a promise in an outer scope

I need a simple function that returns the name. Here's my existing code snippet: getName(entity, id) { const promise = userServices.getName(entity, id).then((data) => { return data; }); / ...

"Customize the appearance of ng-bootstrap datepicker selection with a unique

Having trouble with the ng-bootstrap datepicker when selecting style for month and year. https://i.sstatic.net/grlK6.png The issue seems to be with the select style. select[_ngcontent-c21] { -ms-flex: 1 1 auto; flex: 1 1 auto; padding: 0 .5re ...

Tips for sending information from a controller to jQuery (Ajax) in CodeIgniter

Code snippet in controller: $rates['poor'] = 10; $rates['fair'] = 20; $this->load->view('search_result2', $rates); //Although I have attempted different ways, the only successful method is using the code above. Other ...

Where should JSON data be sourced from when developing a service in AngularJS?

Just starting out with Angular! Am I correct in assuming that when creating a service, you request JSON data from a server controlled by someone else? For example, if I wanted to develop a Weather app, where could I find the JSON data? Is there a standar ...

What is the process for creating static pages that can access local data within a NextJS 13 application?

I recently completed a blog tutorial and I must say, it works like a charm. It's able to generate dynamic pages from .md blog posts stored locally, creating a beautiful output. However, I've hit a roadblock while attempting what seems like a sim ...