CodeBreaker
CodeBreaker

Reputation: 87

How to close all other divs when a new button is clicked?

I have a button group with 5 buttons. I wanted onclick event of the button to toggle 5 different divs. Clicking on button 1 opened/closed div 1, clicking on button 2 opened/closed div 2 and so on. The divs are simply texts here.

1st click on a button --> Shows the div 2nd click on the button --> Hides the div

However, when I click a button only once and it’s div displays and I click another button, the other div stacks on top of the first div. I can close the 1st div if I click its button twice but I want the divs to close even if a different button is clicked. How can I achieve that?

I have attached jsfiddle for what I have so far.

I saw similar question posted couple of times but none of the solution seemed fit for me. Any help would be greatly appreciated.

  function togglediv(id) {
            var div = document.getElementById(id);
            div.style.display = div.style.display == "none" ? "block" : "none";
        }
<div class="myButtons">
  <div class="btn-group" id="MatchingEntitiesButtons">

  <button id="Button1" class="roundBtns" onclick="togglediv('NamesTable')" type="button" > List of Names </button>

  <button id="Button2" class="roundBtns" onclick="togglediv('PhoneTable')" type="button"> List of Address </button>

  <button  id="Button3" class="roundBtns" onclick="togglediv('AddressTable')" type="button" > List of Phone#</button>

  <button id="Button4" class="roundBtns" onclick="togglediv('GradesTable')" type="button"> List of Grades</button>

  <button id="Button5" class="roundBtns" onclick="togglediv('SchoolTable')" type="button"> List of Schools </button>  

  </div>
</div>

<div id ="NamesTable" class="TableBody" style="display:none">Names </div>
<div id ="PhoneTable" class="TableBody" style="display:none">Address </div>
<div id ="AddressTable" class="TableBody" style="display:none">Phone# </div>
<div id ="GradesTable" class="TableBody" style="display:none">Grades </div>                  
<div id ="SchoolTable" class="TableBody" style="display:none">School </div>

Upvotes: 1

Views: 5884

Answers (3)

Scott Marcus
Scott Marcus

Reputation: 65806

Hide all the div elements when any button gets clicked and then display just the one that needs displaying.

But, change your approach a bit:

  • Don't use inline HTML event attributes, such as onclick. There are a bunch of reasons not to use this 25+ year old technique that just will not die.
  • Use Event Delegation to be able to set up a single event handler, but react according to which specific button got clicked.
  • Get rid of ids. Using ids makes your code brittle because you need to constantly update the code to account for new elements.
  • Don't use inline styles - - use CSS classes instead. This eliminates redundant code and makes for overriding applied styles easier.

var clickedBtnIndex = null;
var shownDiv = null;

// Get all the buttons and divs into Arrays:
let buttons = Array.prototype.slice.call(document.querySelectorAll(".roundBtns"));
let divs = Array.prototype.slice.call(document.querySelectorAll(".TableBody"));

// Set up a single click event handler on the parent element of the buttons
document.querySelector(".btn-group").addEventListener("click", function(evt){ 

  // evt.target is a reference to the specific button that triggered the event
  clickedBtnIndex = buttons.indexOf(evt.target); // Get the index of the clicked button within its group

  // If a button was clicked
  if(evt.target.classList.contains("roundBtns")){
     
     // Loop over the divs
     divs.forEach(function(div){
        // Check to see if it is currently being shown
        if(!div.classList.contains("hidden")){
           shownDiv = div;
        }
     });
  
     hideAll();  // Hide all the divs
     
     // Show/hide just the one that was clicked
     if(divs[clickedBtnIndex] === shownDiv){
       divs[clickedBtnIndex].classList.add("hidden");
       shownDiv = null;
     } else {
       divs[clickedBtnIndex].classList.remove("hidden");  
     }
     
     // Store a reference to the index of the button within its group that was clicked
     clickedBtnIndex = buttons.indexOf(evt.target);
  }

});

// This will hide all the divs
function hideAll(){
  // Loop over the array
  divs.forEach(function(div){
    div.classList.add("hidden");  // Add the hidden class
  });
}
.hidden { display:none; }
<div class="myButtons">
  <div class="btn-group" id="MatchingEntitiesButtons">
    <button class="roundBtns" type="button">List of Names</button>
    <button class="roundBtns" type="button">List of Address</button>
    <button class="roundBtns" type="button">List of Phone#</button>
    <button class="roundBtns" type="button">List of Grades</button>
    <button class="roundBtns" type="button">List of Schools</button>  
  </div>
</div>

<div class="TableBody hidden">Names</div>
<div class="TableBody hidden">Address</div>
<div class="TableBody hidden">Phone#</div>
<div class="TableBody hidden">Grades</div>                  
<div class="TableBody hidden">School</div>

But to really make this much simpler, get rid of the separate divs to be shown or hidden and just use one div as a placeholder. Then, just change the contents of that single div.

// Store the data that will need to be displayed in an object that
// has properties that store the arrays of actual data
var data = {
  names: ["Scott","Mary","Tom"],
  addresses: ["10 Main", "23 Elm", "43 Standish"],
  phoneNums: ["555-555-5555","123-456-7890"],
  grades: ["C", "B-", "A+"],
  schools: ["District 1", "District 2", "District 3"]
};

// These map to the object properties and will be used to extract the right data
var keyNames = ["names", "addresses", "phoneNums", "grades", "schools"];

var output = document.querySelector(".output"); // The output element

// Get all the buttons and divs into Arrays:
let buttons = Array.prototype.slice.call(document.querySelectorAll(".roundBtns"));

// Set up a single click event handler on the parent element of the buttons
document.querySelector(".btn-group").addEventListener("click", function(evt){

  // Get the index of the button that was clicked within its group
  var clickedIndex = buttons.indexOf(evt.target);
  
  // Inject the string into the output div
  output.innerHTML = data[keyNames[clickedIndex]].join("<br>");;
});
<div class="myButtons">
  <div class="btn-group" id="MatchingEntitiesButtons">
    <button class="roundBtns" type="button">List of Names</button>
    <button class="roundBtns" type="button">List of Address</button>
    <button class="roundBtns" type="button">List of Phone#</button>
    <button class="roundBtns" type="button">List of Grades</button>
    <button class="roundBtns" type="button">List of Schools</button>  
  </div>
</div>

<div class="output"></div>

And, to really reduce the complexity, don't bother with a separate div for each button that gets clicked. Just have one div and simply change what's in it depending on what button gets clicked:

Upvotes: 0

epascarello
epascarello

Reputation: 207511

Using a class would make this a lot easier. You can select the elements with the active class and remove it.

function togglediv(id) {

  var div = document.getElementById(id);

  document.querySelectorAll(".TableBody.active").forEach(function(elem) {
    if (elem !== div) elem.classList.remove("active");
  });

  // toggle the class to the section that was clicked.
  div.classList.toggle("active");

}
.TableBody {
  display: none;
}

.TableBody.active {
  display: block;
}
<div class="myButtons">
  <div class="btn-group" id="MatchingEntitiesButtons">

    <button id="Button1" class="roundBtns" onclick="togglediv('NamesTable')" type="button"> List of Names </button>

    <button id="Button2" class="roundBtns" onclick="togglediv('PhoneTable')" type="button"> List of Address </button>

    <button id="Button3" class="roundBtns" onclick="togglediv('AddressTable')" type="button"> List of Phone#</button>

    <button id="Button4" class="roundBtns" onclick="togglediv('GradesTable')" type="button"> List of Grades</button>

    <button id="Button5" class="roundBtns" onclick="togglediv('SchoolTable')" type="button"> List of Schools </button>

  </div>
</div>

<div id="NamesTable" class="TableBody">Names </div>
<div id="PhoneTable" class="TableBody">Address </div>
<div id="AddressTable" class="TableBody">Phone# </div>
<div id="GradesTable" class="TableBody">Grades </div>
<div id="SchoolTable" class="TableBody">School </div>

Without using the class, you can just use a loop and set it to be hidden

document.querySelectorAll(".TableBody")
  .forEach(function (elem) {
    elem.style.display = "none";
  })

This code is not going to toggle. If you need to toggle, it is as simple as checking to see if the element is the current one you have.

var active = doucument.getElementById(id);
document.querySelectorAll(".TableBody")
  .forEach(function (elem) {
    if (elem !== active) {
      elem.style.display = "none";
    }
  })

Upvotes: 0

Barmar
Barmar

Reputation: 781088

Loop through all the DIVs. If it's the specified DIV, toggle it, otherwise hide it.

function togglediv(id) {
  document.querySelectorAll(".TableBody").forEach(function(div) {
    if (div.id == id) {
      // Toggle specified DIV
      div.style.display = div.style.display == "none" ? "block" : "none";
    } else {
      // Hide other DIVs
      div.style.display = "none";
    }
  });
}
<div class="myButtons">
  <div class="btn-group" id="MatchingEntitiesButtons">

    <button id="Button1" class="roundBtns" onclick="togglediv('NamesTable')" type="button"> List of Names </button>

    <button id="Button2" class="roundBtns" onclick="togglediv('PhoneTable')" type="button"> List of Address </button>

    <button id="Button3" class="roundBtns" onclick="togglediv('AddressTable')" type="button"> List of Phone#</button>

    <button id="Button4" class="roundBtns" onclick="togglediv('GradesTable')" type="button"> List of Grades</button>

    <button id="Button5" class="roundBtns" onclick="togglediv('SchoolTable')" type="button"> List of Schools </button>

  </div>
</div>

<div id="NamesTable" class="TableBody" style="display:none">Names </div>
<div id="PhoneTable" class="TableBody" style="display:none">Address </div>
<div id="AddressTable" class="TableBody" style="display:none">Phone# </div>
<div id="GradesTable" class="TableBody" style="display:none">Grades </div>
<div id="SchoolTable" class="TableBody" style="display:none">School </div>

Upvotes: 5

Related Questions