-1

How do I write something in Javascript so one thing happens when two buttons are hit?

For example, I want something like this

<button>A</button>
<button>B</button>
<img id = "pics" src = "/randompicture.gif">

And in JS, I want to be able to make something visible when both button A and B are selected.

If(button A is hit AND button B is hit){
then this happens, 
such as document.getElementById("pics").visibility = "hidden"}

Thank you

PS: Sorry for bad syntax. I'm new to HTML, CSS and JS. Any help is greatly appreciated.

Edit: By "selecting", I mean when both buttons are pressed at least once

Edit 2: Just tried @ Khauri McClain's event listeners suggestion in repl.it. It seems to have worked, I got what I wanted. Here's what I wrote

document.getElementById("buttonWithFirstId").addEventListener("click", function(){
     document.getElementById("buttonWithSecondId").addEventListener("click", function(){
         document.getElementById("imageId").style.visibility = "visible"
     });
});

Edit 3: Wow, there's a lot of ways of doing this, it seems. I'm excited to try these. Thank you for all these different suggestions.

Thank you everyone for your suggestions.

  • 2
    This sounds like a task better suited to checkboxes than buttons. – Quentin Mar 25 '18 at 15:26
  • @Quentin I thought of doing that, but I really want to stick with buttons if possible. I think checkboxes are a 'plan B' for me if this doesn't work – dolphin supreme Mar 25 '18 at 15:28
  • 1
    and how you can **select** a button ? what selecting a button mean ? – Temani Afif Mar 25 '18 at 15:28
  • What in particular do you mean by "select"? A button can be pressed or focused, but two buttons cannot be focused at once (without a little creativity anyway). Or do you want the action to happen when the user clicks both the buttons at least once? In any case you'll be using [event listners](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener) – Khauri Mar 25 '18 at 15:30
  • Logically you need to track when and which buttons are clicked. Why don't you start with that much and post a question if you have a problem. Do some searching on the internet about "how to track when buttons are clicked in JavaScript" and see what comes up. – Heretic Monkey Mar 25 '18 at 15:34
  • What if the user clicks a button twice, does this de-select that button? checkbox already has this definition, theres no need to reinvent the wheel. Why do you want to use a button as plan A, and checkbox as plan B? Is it just because of the aesthetics/appearance? You can change a checkbox to appear as a button. – George Mar 25 '18 at 15:38
  • Possible duplicate of [How to check whether a Button is clicked by using JavaScript](https://stackoverflow.com/questions/2788191/how-to-check-whether-a-button-is-clicked-by-using-javascript) – Heretic Monkey Mar 25 '18 at 15:38
  • Your selected "answer" is incorrect and doesn't work properly. It's also overly complicated. See my answer below. – Scott Marcus Mar 25 '18 at 16:47

4 Answers4

2

You can use a CSS class that is added/removed to each button to act as a "flag" as to whether or not the button has been clicked. Then, use the Array.every()]1 method (to check that every button has that class).

NOTE: Your code to set the visibility is incorrect. You can't access CSS properties directly from the DOM object, you have to first access the .style property of the DOM object. Usually, it's better to set up a CSS class ahead of time and just apply or remove the class from the element.

So, when you want to access the classes that an element has, you can use the .classList property:

element.classList.add("className")      // adds the class
element.classList.remove("className")   // removes the class
element.classList.contains("className") // returns true/false

This solution will work no matter how many buttons you need to be clicked and I've added some more buttons to show this. I've also added a little additional CSS for a visual indicator.

// Get all related buttons into an array
var btns = Array.prototype.slice.call(document.querySelectorAll(".hit"));
var img = document.getElementById("pics"); // Get reference to image

// Loop over the button array
btns.forEach(function(btn){

  // Set up a click event handler for each button
  btn.addEventListener("click", function() {
    // Add or remove a CSS class that tracks the current "hit" state of the button
    // and creates a visual cue as to its state based on whether the class is already applied.
    this.classList.contains("clicked") ? 
      this.classList.remove("clicked") : this.classList.add("clicked");

    // If all the buttons have the clicked class hide the image otherwise don't
    btns.every((b) => { return b.classList.contains("clicked"); }) ?
      pics.classList.add("hidden") : pics.classList.remove("hidden");      
  });
});
/* These pre-made classes will be applied/removed as necessary. */
.clicked { box-shadow:0 0 5px rgba(255, 0, 0, .5) }
.hidden  { visibility:hidden; }
<button class="hit">A</button>
<button class="hit">B</button>
<button class="hit">C</button>
<button class="hit">D</button>
<img id = "pics" src = "/randompicture.gif" alt="Image Here">
Scott Marcus
  • 64,069
  • 6
  • 49
  • 71
  • 1
    Pretty clean answer. I just want to point out that you don't need to pre-define data-hit if you use booleans. `i.e. this.dataset.hit = true` and `return b.dataset.hit` And not that it matters because in OP's case he's just hiding an image, but this will also perform the action after all buttons have been clicked if the user clicks the buttons again. – Khauri Mar 25 '18 at 16:01
  • 2
    @KhauriMcClain Thanks. Yes, I know the answer doesn't address a second click on a button, but the OP didn't state that as a requirement, so I didn't include it. – Scott Marcus Mar 25 '18 at 16:03
  • 1
    @KhauriMcClain Ah, what the heck. I've updated the code to be able to unclick a button. – Scott Marcus Mar 25 '18 at 16:16
  • 1
    @KhauriMcClain Answer edited for much simpler approach. – Scott Marcus Mar 25 '18 at 16:37
  • This works fine, of course, but FWLIW I thought the data attribute approach you had before was clearer. – Daniel Beck Mar 25 '18 at 17:10
  • @DanielBeck This works in the same way, but instead of tracking a `data-` attribute and adding/removing a style class, it just uses the class to accomplish both jobs. I think that makes it much simpler. – Scott Marcus Mar 25 '18 at 17:14
  • Yeah, I'm nitpicking based on personal preference, I guess -- I tend to try to use data attributes for data and classnames for styling, which is what you were doing the first time through. – Daniel Beck Mar 25 '18 at 17:18
  • @DanielBeck True and that makes sense, but here the class is for styling, so also using it for logic isn't a stretch or violating the "spirit" of CSS. – Scott Marcus Mar 25 '18 at 17:19
  • That's totally fair, sure. – Daniel Beck Mar 25 '18 at 17:21
1

You could track the state of the buttons. Please note that the following implementation allows the user to toggle the state of each button between clicked and not clicked. If you want the button to be considered clicked once the user has clicked independently if the user clicks on the button again just change the line that says state[buttonClicked] = !state[buttonClicked] to state[buttonClicked] = true.

const state = {A: false, B: false};

addEventListener('click', (e) => {
   const buttonClicked = e.target.innerHTML;
   state[buttonClicked] = !state[buttonClicked];
  
   console.log(Object.values(state));
  
   if(Object.values(state).includes(false)) {
     console.log('not all buttons are clicked');
   } else {
     console.log('all buttons are clicked');
     // Do what you got to do here
     document.getElementById("pics").style.visibility = "hidden";
   }
});
<button>A</button>
<button>B</button>
<br/>
<img id = "pics" src ="http://placehold.it/200x200" />
Vinicius Santana
  • 3,936
  • 3
  • 25
  • 42
0

You could keep track of which buttons were selected by adding/removing them from an array. When both buttons are in the array, perform your action.

This will add the button to the array if it isn't in the array. If the button is clicked again and it is in the array it will be removed.

let clicked = []

Array.from(document.querySelectorAll('button')).forEach(btn => {
  btn.addEventListener('click', e => {
    // The clicked button
    let target = e.currentTarget
    // Test if the button is in the array
    let idx = clicked.indexOf(target)
    // If it isn't in the array add it
    if (idx == -1) clicked.push(target)
    // Otherwise remove it
    else clicked.splice(idx, 1)
    
    // Test the length of the array.
    // Note: there might be a more dynamic way to do this
    // however, this is the simplest way.
    if (clicked.length == 2) {
      myAction()
    }
  })
})

function myAction() {
  console.log('both buttons clicked!')
}
<button id="a">A</button>
<button id="b">B</button>
Get Off My Lawn
  • 34,175
  • 38
  • 176
  • 338
0

try this function adding :

function clickedbutton(e) {
  /* Check if button has class selected */
  if (e.classList.contains("selected")) {
    e.classList.remove("selected");
    /* removit if clicked twice */
  } else {
    /* Addit if not */
    e.className += " selected";
  }
  /* loop trow all button */
  var btn = document.getElementsByTagName("button");
  var i;
  var check=0;
  for (i = 0; i < btn.length; i++) {
    if (btn[i].classList.contains("selected")) {
      check++;
    } else {
      check--;
    }
  }
  console.log(check);
  /* if the button has the class selected then change pic src */
  if (check == 2) {
    document.getElementById("pics").src = "https://media.gadventures.com/media-server/cache/a4/b7/a4b727085661bdaa6cc94e84fbe21039.jpg";
  } else {
    document.getElementById("pics").src = "http://artofabsence.com/wp-content/uploads/2012/09/camel-ride1.jpg";
  }
}
.selected {
  border: 1px solid #999999;
  background-color: #cccccc;
  color: #666666;
}

img {
  width: 150px
}
.as-console-wrapper {
    max-height: 50px !important;
}
<button onclick="clickedbutton(this);">A</button>
<button onclick="clickedbutton(this);">B</button>
<img id="pics" src="http://artofabsence.com/wp-content/uploads/2012/09/camel-ride1.jpg">
M0ns1f
  • 2,705
  • 3
  • 15
  • 25
  • 1
    That regex + string manipulation on the className is needlessly complex. Why not just `e.classList.contains('selected')`? – Daniel Beck Mar 25 '18 at 16:00
  • If you click A then B, the picture changes.But, if you then click A again, it does not revert back. Now, if you click A and then B, the picture changes and then if you click B, the picture does change back. -1 for answer that doesn't work. – Scott Marcus Mar 25 '18 at 16:01
  • `(" " + e.className + " ").replace(/[\n\t]/g, " ").indexOf(" selected ") > -1` is pretty overcomplicated. If you're using `e.classList.remove` then you might as well use `e.classList.add` and `e.classList.contains`. But if you're using regex you maybe could have just done `/\bselected\b/gi.test(e.className)` – Khauri Mar 25 '18 at 16:09
  • 1
    @DanielBeck added `e.classList.contains('selected')` nice suggestion , @ScottMarcus changed check from bool to int now everything is finded , µ – M0ns1f Mar 25 '18 at 16:59