1

I have css and js on a button group so that when you click a button from the group it shows as active, and when you click a different button, that button becomes active and the rest are cleared. I have to have 22 of these button groups (I only put 2 here for the sake of space) on my page, when I have just one the code works, but when I add the others everything comes crumbling down, can anyone help! How do use the script multiple times, where the script is applied to every group and doesn't intervene with the others.

function codeAddress() {
  var header = document.getElementById("myDIV");
  var btns = header.getElementsByClassName("btn");
  for (var i = 0; i < btns.length; i++) {
    btns[i].addEventListener("click", function() {
      var current = document.getElementsByClassName("active");
      current[0].className = current[0].className.replace(" active", "");
      this.className += " active";
    });
  }
}
window.onload = codeAddress;
.btn {
  background-color: white;
  border: 3px solid #0099ff;
  color: #0099ff;
  cursor: pointer;
  float: left;
  padding: 10px 16px;
  font-size: 18px;
}

.active,
.btn:hover {
  background-color: #0099ff;
  color: white;
  border: 3px solid #0099ff;
  cursor: pointer;
}
<div id="myDIV">
  <button class="btn active">GQL</button>
  <button class="btn">PSV</button>
  <button class="btn">WT2</button>
  <button class="btn">NBV</button>
  <button class="btn">MBD</button>
</div>
<div id="myDIV">
  <button class="btn active">GQL</button>
  <button class="btn">PSV</button>
  <button class="btn">WT2</button>
  <button class="btn">NBV</button>
  <button class="btn">MBD</button>
</div>
Jack Bashford
  • 43,180
  • 11
  • 50
  • 79
Joshua D.
  • 13
  • 1
  • 5
  • There should be only one ID per document. If you have more than one element with the same ID you are doing something wrong and should consider using `class` instead – vol7ron Nov 12 '18 at 02:45
  • Well you have to copy and paste the js and then change the header line to get the other ID and you would do this for each ID. I wouldn't suggest using the ID approach as you copy the js 21 times as you have 22 groups. Use the class approach like he mentioned. You can add as many group and you don't have to alter any js. – Mohammad C Nov 12 '18 at 12:18

5 Answers5

4

Here give this ago. I believe this is the intended response you expect when clicking button from different groups. Something like radio buttons. As already mentioned an ID can only represent one element not several. Use class instead. So i have changed your id to a class btn-group.

function codeAddress() {
    const btnClick = function () {
        this.parentNode.getElementsByClassName("active")[0].classList.remove("active");
        this.classList.add("active");
    };
    document.querySelectorAll(".btn-group .btn").forEach(btn => btn.addEventListener('click', btnClick));

    // This is the same as above just another way of doing it. use which ever you like
    // var btns = document.querySelectorAll(".btn-group .btn");
    // for (var i = 0; i < btns.length; i++) {
    //     btns[i].addEventListener("click", function () {
    //         this.parentNode.getElementsByClassName("active")[0].classList.remove("active");
    //         this.classList.add("active");
    //     });
    // }
   
}
window.onload = codeAddress;
.btn {
    background-color: white;
    border: 3px solid #0099ff;
    color: #0099ff;
    cursor: pointer;
    float: left;
    padding: 10px 16px;
    font-size: 18px;
}

.active,
.btn:hover {
    background-color: #0099ff;
    color: white;
    border: 3px solid #0099ff;
    cursor: pointer;
}
<div class="btn-group">
    <button class="btn active">GQL</button>
    <button class="btn">PSV</button>
    <button class="btn">WT2</button>
    <button class="btn">NBV</button>
    <button class="btn">MBD</button>
</div>
<br style="clear:both">
<div class="btn-group">
    <button class="btn active">GQL</button>
    <button class="btn">PSV</button>
    <button class="btn">WT2</button>
    <button class="btn">NBV</button>
    <button class="btn">MBD</button>
</div>
Mohammad C
  • 1,321
  • 1
  • 8
  • 12
  • 1
    Thank you so much for the help! This is the exactly what I was hopping to accomplish, thanks as well for providing both solutions that way I can tailor it to my needs as I go. Really Appreciate it! – Joshua D. Nov 13 '18 at 17:08
2

Here the example what you need https://jsbin.com/bomegabiqo/1/edit?html,js,output

First of all, I want to say that you don't need to have two div with the same id The second point is that you need to attach eventListener to the parent element, due to best-practice and performance optimization (you can read about it somewhere)

So here is updated version of HTML:

<div id="myGroupButtonsWrapper">  
  <div id="myDIV">
    <button class="btn active">GQL</button>
    <button class="btn">PSV</button>
    <button class="btn">WT2</button>
    <button class="btn">NBV</button>
    <button class="btn">MBD</button>
  </div>
  <div id="myDIVV">
    <button class="btn">GQL</button>
    <button class="btn">PSV</button>
    <button class="btn">WT2</button>
    <button class="btn">NBV</button>
    <button class="btn">MBD</button>
  </div>
</div>

And JavaScript:

function codeAddress() {

  function myClickCallback(e) {
    if (e.target.className === 'btn') {
      var allButtons = document.querySelectorAll("#myGroupButtonsWrapper .btn");

      allButtons.forEach((elem) => {
        elem.className = elem.className.replace(" active", "");           
      });
      e.target.className += ' active';    
    } else {
      return;
    }
  }

  var header = document.getElementById("myGroupButtonsWrapper");   
  header.addEventListener("click", myClickCallback);    
} 
window.onload = codeAddress;
pepsilike
  • 206
  • 1
  • 7
1

It's not working because you have multiple IDs:

<div id="myDIV">...</div>
<div id="myDIV">...</div>

You can't do this - first, it's invalid HTML, and second, it'll do one of two things with the JS: cause an error, which you can see in the console, or it'll treat header as a NodeList, which is a collection of nodes that match the query selection, which means that it won't work. If you make them all have different IDs (e.g. div1, div2, div3, etc), it'll work if you modify your code to take multiple divs.
The other option is to make a class (e.g. myDIV) and modify your existing JavaScript code to use a class.

Jack Bashford
  • 43,180
  • 11
  • 50
  • 79
  • If I was to take the different IDs approach, what would I need to modify on the JS to get this to work? (I'm just a Beginner when it comes to code, so sorry if the question is redundant) – Joshua D. Nov 12 '18 at 02:49
1

Instead of individual buttons, I would recommend using radio buttons for something like this. It already has functionality built in to group together for a selection similar to what you're going for. Then you just have to use built in commands to set the active button or check the values.

https://www.w3schools.com/jsref/prop_radio_checked.asp

https://www.w3schools.com/html/html_forms.asp

Tim Hunter
  • 242
  • 1
  • 7
1

it is fairly simple to accomplish this using just 3 steps.

// First step is to create a onBtnClick handler function:
// The btn which was clicked can be accessed from event.target
// And then we can use the build in function classList.toggle to toggle the active class on that btn
const onBtnClickHandler = function (ev){ev.target.classList.toggle("active")};

// Next step is to find all btns, this can be done using the build in querySelectorAll function
const btns = document.querySelectorAll('.btn'); //returns NodeList array

// Last step is to add the eventListener callback function to each btn
btns.forEach(btn => btn.addEventListener('click', onBtnClickHandler));

Hope this helps.

Andresson
  • 1,257
  • 10
  • 15