I am creating a dashboard with approximately 20 divs starting with "display: none;".
When the .onClick() in the sidebar will be used, it will show a specific div and keep hidden all the others. I have used the classic solution of creating a function for each div, however, is extremely lengthy and the code looks like a mess.
Is there a better cleaner way to achieve this with Javascript?
Here is my code:
function presale() {
var x = document.getElementById("presale");
var y = document.getElementById("claim");
var z = document.getElementById("stake");
if (x.style.display === "grid") {
x.style.display = "none";
} else {
x.style.display = "grid";
y.style.display = "none";
z.style.display = "none";
}
}
function claim() {
var x = document.getElementById("presale");
var y = document.getElementById("claim");
var z = document.getElementById("stake");
if (y.style.display === "grid") {
y.style.display = "none";
} else {
x.style.display = "none";
y.style.display = "grid";
z.style.display = "none";
}
}
function stake() {
var x = document.getElementById("presale");
var y = document.getElementById("claim");
var z = document.getElementById("stake");
if (z.style.display === "grid") {
z.style.display = "none";
} else {
x.style.display = "none";
y.style.display = "none";
z.style.display = "grid";
}
}
*,
html {
color: #fff;
background-color: black;
}
#presale,
#claim,
#stake
/* Here I have many other divs like below */
{
display: none;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js"></script>
<link rel="stylesheet" href="MOD.CSS">
<script src="main2.js"></script>
<title>Base Template</title>
</head>
<body>
<div>
<ul>
<!-- Here I have other 20 options like the above -->
<li onclick="presale()">Presale</li>
<li onclick="claim()">Claim</li>
<li onclick="stake()">Stake</li>
<!-- Here I have other 20 options like the above -->
</ul>
<div id="presale">
<h1>Presale</h1>
</div>
<div id="claim">
<h1>Claim</h1>
</div>
<div id="stake">
<h1>Stake</h1>
</div>
</div>
</body>
</html>
Is there a better way to do this without the need to create a function and repeat the same thing over and over for each div?
CodePudding user response:
Here you see a vanilla Javascript solution.
content
divs are by default hidden.
If you click an element, the corresponding data-id
get the class show
.
window.onload = function () {
document.querySelectorAll('#nav li').forEach((elements) => {
elements.addEventListener('click', (el) => {
document.querySelectorAll('.content').forEach((item) => {
// hide all
item.classList.remove('show');
});
// show one
document.getElementById(el.target.getAttribute('data-id')).classList.add('show');
});
});
};
.content {
display: none;
}
.show {
display: block;
}
<ul id="nav">
<li data-id="presale">Presale</li>
<li data-id="claim">Claim</li>
<li data-id="stake">Stake</li>
</ul>
<div id="presale" >
<h1>Presale</h1>
</div>
<div id="claim" >
<h1>Claim</h1>
</div>
<div id="stake" >
<h1>Stake</h1>
</div>
CodePudding user response:
This is a question for Code Review section https://codereview.stackexchange.com/
However, try smth like this:
const elems = ["presale", "claim", "stake"];
function toggle(elem) {
elems.map(i => {
let el = document.getElementById(i);
if (el.style.display === "grid") {
el.style.display = "none";
} else {
el.style.display = "grid";
}
})
}
and in html add the elem name as a param, so, replace this
<li onclick="presale()">Presale</li>
<li onclick="claim()">Claim</li>
<li onclick="stake()">Stake</li>
with this
<li onclick="toggle('presale')">Presale</li>
<li onclick="toggle('claim')">Claim</li>
<li onclick="toggle('stake')">Stake</li>
CodePudding user response:
You could simply assign the same class (e.g. my_div
) to every showable div
, then pass the id
to your function (that will show that and hide all the others).
function show_hide(id) {
document.querySelectorAll('.my_div').forEach(my_div => {
my_div.style.display = my_div.getAttribute('id') == id ? 'block' : 'none';
});
}
.my_div {
display: none;
}
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js"></script>
<div>
<ul>
<li onclick="show_hide('presale')">Presale</li>
<li onclick="show_hide('claim')">Claim</li>
<li onclick="show_hide('stake')">Stake</li>
</ul>
<div id="presale">
<h1>Presale</h1>
</div>
<div id="claim">
<h1>Claim</h1>
</div>
<div id="stake">
<h1>Stake</h1>
</div>
</div>
CodePudding user response:
Something like this using data attributes and classlist toggles should also work.
I would consider minimizing your code (and CSS) by using generic CSS selectors to hide/show the individual sections. This also makes scalability and maintainability easier for the next guy.
This has the added benefit of your styling being controlled 100% using CSS and not arbitrary inline styles set by the javascript.
Adding another section is also easy as can be:
- Add a new section with some id (eg.
awesome-section
) - Add a nav entry with the attribute
data-toggle-section
with the id as the value<li data-toggle-section="awesome-section">Awesome Section</li>
- Profit
You're also not restricted to using just the nav elements themselves as the event listener is bound using the [data-toggle-section]
selector which means that basically anything can show or hide a section as long as it has that attribute with the correct value.
const buttons = Array.from(document.querySelectorAll("[data-toggle-section]"));
const sections = buttons.map(element => {
return document.getElementById(element.attributes['data-toggle-section'].value)
});
buttons.forEach(element => {
element.addEventListener('click', event => {
const selected = element.attributes['data-toggle-section'].value;
sections.forEach(section => {
if(section.id === selected) {
section.classList.toggle('shown')
} else {
section.classList.remove('shown');
}
})
});
});
*,
html {
color: #fff;
background-color: black;
}
.option-section {
display: none;
}
.option-section.shown {
display: grid;
}
<div>
<ul>
<!-- Here I have other 20 options like the above -->
<li data-toggle-section="presale">Presale</li>
<li data-toggle-section="claim">Claim</li>
<li data-toggle-section="stake">Stake</li>
<!-- Here I have other 20 options like the above -->
</ul>
<div id="presale" >
<h1>Presale</h1>
</div>
<div id="claim" >
<h1>Claim</h1>
</div>
<div id="stake" >
<h1>Stake</h1>
</div>
</div>
CodePudding user response:
If you attach data attributes to both the list items and the "panels" you can use one function to match them up, and use a CSS class to determine whether it should be active or not.
// Cache the panels container, and the list element
// adding one event listener to the list. We're using
// event delegation for this - one listener captures all
// the events from its child elements
const panels = document.querySelector('.panels');
const list = document.querySelector('ul');
list.addEventListener('click', handlePanel);
// When the listener is triggered
function handlePanel(e) {
// Check if it's a list item
if (e.target.matches('li')) {
// Destructure its id from the dataset
const { id } = e.target.dataset;
// Remove all the active classes from the panels
panels.querySelectorAll('.panel').forEach(panel => {
panel.classList.remove('active');
});
// And then add an active class to the panel which
// matches the id from the list item
const current = panels.querySelector(`.panel[data-id="${id}"]`);
current.classList.add('active')
}
}
.panel { display: none; }
ul { list-style-type: none; margin-left: 0; padding: 0; }
li { padding: 0.3em; }
li:hover { background-color: thistle; cursor: pointer; }
.active { display: block; }
<ul >
<li data-id="presale">Presale</li>
<li data-id="claim">Claim</li>
<li data-id="stake">Stake</li>
</ul>
<div >
<div data-id="presale" >
<h1>Presale</h1>
</div>
<div data-id="claim" >
<h1>Claim</h1>
</div>
<div data-id="stake" >
<h1>Stake</h1>
</div>
</div>
CodePudding user response:
Here's my attempt :
- For each line, I add an event on click.
- On event, I select one
.action
(only one with.querySelector()
because you only want one shown, you need to usequerySelectorAll
for more) that doesn't haved-none
wich means that is the one shown, and I hide it. - I select the concerned action with the
data-id
and remove.d-none
to show it
document.querySelectorAll("li").forEach(e => e.addEventListener("click", () => {
if(document.querySelector(".action:not(.d-none)")){
document.querySelector(".action:not(.d-none)").classList.add("d-none")
}
document.getElementById(e.dataset.id).classList.remove("d-none")
}))
.action{
display:grid;
}
.d-none{
display:none;
}
<ul>
<li data-id="presale">Presale</li>
<li data-id="claim">Claim</li>
<li data-id="stake">Stake</li>
</ul>
<div id="presale">Presale</div>
<div id="claim">Claim</div>
<div id="stake">Stake</div>