'Display none some content and block one element
I would like to make 3 buttons with each one make all the content div to display: none and depending on the button you have click one of the content div change to display: block. For example, If I click on the second button It will show only the second div content.
function showPanel(id) {
var elements = document.getElementsByClassName("content");
for (let i = 0; i < elements.length; i++) {
document.getElementById(i).style.display = "none";
}
document.getElementById(id).style.display = "block";
}
<button onclick="showPanel('1')">test1</button>
<button onclick="showPanel('2')">test2</button>
<button onclick="showPanel('3')">test3</button>
<div class="content">
<div id="1" class="content">
<p>TEST1</p>
</div>
<div id="2" class="content">
<p class="other">TEST2</p>
</div>
<div id="3" class="content ">
<p class="other">TEST3</p>
</div>
</div>
Solution 1:[1]
Multiple issues.
- Length can be calculated using
elements.lengthand notelements.length() - You have given same class name to both the parent and the child divs. So hiding all elements with class name
contentwill hide your whole parents itself. So after updatingstyle.display = "block"to the required target, it will not work. Because your parent is alreadystyle.display = "none". So you should make a logic update there. So I changed the parent class name.
function showPanel(id) {
var elements = document.getElementsByClassName("content");
for (let i = 0; i < elements.length; i++) {
elements[i].style.display = "none";
}
document.getElementById(id).style.display = "block";
}
<button onclick="showPanel('1')">test1</button>
<button onclick="showPanel('2')">test2</button>
<button onclick="showPanel('3')">test3</button>
<div>
<div id="1" class="content">
<p>TEST1</p>
</div>
<div id="2" class="content">
<p class="other">TEST2</p>
</div>
<div id="3" class="content ">
<p class="other">TEST3</p>
</div>
</div>
Solution 2:[2]
No need for JS or Jquery. Instead of a button you can use an anchor tag. Then you calling with the anchor the id of the element. Last but not least you make the boxes hidden through CSS and use the :target selector to display the elements:
.content {
display: none;
}
.content:target {
display: block;
}
<a href="#1">test1</a><br>
<a href="#2">test2</a><br>
<a href="#3">test3</a><br>
<div class="content-container">
<div id="1" class="content">
<p>TEST1</p>
</div>
<div id="2" class="content">
<p class="other">TEST2</p>
</div>
<div id="3" class="content ">
<p class="other">TEST3</p>
</div>
</div>
Solution 3:[3]
A more elegant way I might approach a prob,problem like this would be to tie the panels and their triggers together using data-attributes. This way, you don't risk conflicts with other IDs that m ay be the same on the page (IDs should always be unique).
Before setting up my event listener, I would initialize an openPanel variable and set it to any panel that is already created with the active class name. Whenever we open a new panel, we will overwrite this variable vaklue, so we don't need to do a new querySelctor each time.
Then, in the CSS, rather than hiding all panels and then showing the one with the active class, we can write a single style that hides any panels without the active class using the :not negation selector.
This is how that would look (initializing this with panel #1 open by default, but you can simply remove the active class from it in the HTML if you don't want that):
let openPanel = document.querySelector('[data-panel-id].active');
document.addEventListener('click', e => {
if (e.target?.matches?.('[data-panel-target]')) {
const id = e.target.dataset.panelTarget;
if (id) {
const panel = document.querySelector(`[data-panel-id="${id}"]`);
if (panel) {
openPanel?.classList.remove('active');
panel.classList.add('active');
openPanel = panel;
}
}
}
})
[data-panel-id]:not(.active) {
display: none;
}
<button data-panel-target="1">test1</button>
<button data-panel-target="2">test2</button>
<button data-panel-target="3">test3</button>
<main>
<div data-panel-id="1" class="active">
<p>TEST #1</p>
</div>
<div data-panel-id="2">
<p>TEST #2</p>
</div>
<div data-panel-id="3">
<p>TEST #3</p>
</div>
</main>
Solution 4:[4]
I already submitted a separate solution with my preferred recommendation, but I wanted to provide an answer to your question using the same approach you started with so as not to deviate from the code you already have in place.
The code you already had in place was actually fairly close to working already. The main issue I saw was that you were using document.getElementById(i) where you should actually have been using elements[i]. We can improve this further though, by replacing the for loop with a for..of loop, and determining inline whether the current element being evaluated is the one we want to show. If so, we use 'block', otherwise 'none'.
After initializing our function, we can call it on one of our IDs within the JS to have one panel open by default. **It's also important that the parent of all these .content elements NOT contain the class name content as well, as that would conflict with your function. I have replaced that parent element with a simple <main>…</main> element.
Here is how I would achieve solving this using your existing approach:
function showPanel(contentId) {
const elements = Array.from(document.getElementsByClassName('content'));
for (const element of elements) {
element.style.display = element.id === contentId ? 'block' : 'none';
}
}
showPanel('1');
<button onclick="showPanel('1')">test1</button>
<button onclick="showPanel('2')">test2</button>
<button onclick="showPanel('3')">test3</button>
<main>
<div id="1" class="content">
<p>TEST1</p>
</div>
<div id="2" class="content">
<p>TEST2</p>
</div>
<div id="3" class="content ">
<p>TEST3</p>
</div>
</main>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Nitheesh |
| Solution 2 | |
| Solution 3 | Brandon McConnell |
| Solution 4 | Brandon McConnell |
