Reputation: 4789
How do I keep only one definition visible at the same time in this example:
In other words:
Clicking on
i
button should toggle class on itself and the definition below the term, and removeactive
class from other buttons andopen
class from other definitions.
document.querySelectorAll("dl").forEach(dl =>
dl.addEventListener("click", ({ target }) => {
if (!target.matches("button")) return
target.classList.toggle("active")
target.parentElement.nextElementSibling.classList.toggle("open")
})
)
dd {
visibility: hidden;
height: 0
}
.open {
visibility: visible;
height: auto
}
.active {
color: DeepSkyBlue
}
abbr {
pointer-events: none
}
<dl>
<dt>aluminum
<button type=button><abbr title="See Definition"><i>i</i></abbr></button></dt>
<dd>the chemical element of atomic number 13, a light silvery-grey metal.</dd>
<dt>silver
<button type=button><abbr title="See Definition"><i>i</i></abbr></button></dt>
<dd>a precious shiny greyish-white metal, the chemical element of atomic number 47.</dd>
<dt>gold
<button type=button><abbr title="See Definition"><i>i</i></abbr></button></dt>
<dd>a yellow precious metal, the chemical element of atomic number 79.</dd>
<dt>platinum
<button type=button><abbr title="See Definition"><i>i</i></abbr></button></dt>
<dd>a precious silvery-white metal, the chemical element of atomic number 78.</dd>
</dl>
Upvotes: 2
Views: 311
Reputation: 18515
Here is a more concise solution which uses only open
class to do what you need and some CSS & ES6 features.
The idea is to remove open
to all and then only toggle to the one clicked. Also the entire thing for the removal is chained via ES6 methods.
Also note the .open+dd
CSS selector since you have siblings and not a container class (it would have been easier with such an approach).
document.querySelectorAll("dl").forEach(dl =>
dl.addEventListener("click", ({ target }) => {
if (!target.matches("button")) return
if (!target.parentElement.classList.contains("open"))
[...target.parentElement.parentElement.children]
.filter(({ tagName }) => tagName.toLowerCase() == "dt")
.forEach(element => element.classList.remove("open"))
target.parentElement.classList.toggle("open")
})
)
dd {
visibility: hidden;
height: 0
}
.open + dd {
visibility: visible;
height: auto
}
.open button {
color: DeepSkyBlue
}
abbr {
pointer-events: none
}
<dl>
<dt>aluminum
<button type=button><abbr title="See Definition"><i>i</i></abbr></button></dt>
<dd>the chemical element of atomic number 13, a light silvery-grey metal.</dd>
<dt>silver
<button type=button><abbr title="See Definition"><i>i</i></abbr></button></dt>
<dd>a precious shiny greyish-white metal, the chemical element of atomic number 47.</dd>
<dt>gold
<button type=button><abbr title="See Definition"><i>i</i></abbr></button></dt>
<dd>a yellow precious metal, the chemical element of atomic number 79.</dd>
<dt>platinum
<button type=button><abbr title="See Definition"><i>i</i></abbr></button></dt>
<dd>a precious silvery-white metal, the chemical element of atomic number 78.</dd>
</dl>
Upvotes: 1
Reputation: 2065
It is the same thing but, you don't required to check condition everytime.
You can just use element.classList="";
to remove all give class from element.
No you don't have "active" and "open" class to any element, you need to use .classList.add("open")
instead of .classList.toggle("open")
Check this:
document.querySelectorAll("dl").forEach(dl =>
dl.addEventListener("click", ({ target }) => {
document.querySelectorAll("dd").forEach(function(element) {
element.classList="";
});
document.querySelectorAll(".active").forEach(function(element) {
element.classList="";
});
if (!target.matches("button")) return
target.classList.add("active")
target.parentElement.nextElementSibling.classList.add("open")
})
)
dd {
visibility: hidden;
height: 0
}
.open {
visibility: visible;
height: auto
}
.active {
color: DeepSkyBlue
}
abbr {
pointer-events: none
}
<dl>
<dt>aluminum
<button type=button><abbr title="See Definition"><i>i</i></abbr></button></dt>
<dd>the chemical element of atomic number 13, a light silvery-grey metal.</dd>
<dt>silver
<button type=button><abbr title="See Definition"><i>i</i></abbr></button></dt>
<dd>a precious shiny greyish-white metal, the chemical element of atomic number 47.</dd>
<dt>gold
<button type=button><abbr title="See Definition"><i>i</i></abbr></button></dt>
<dd>a yellow precious metal, the chemical element of atomic number 79.</dd>
<dt>platinum
<button type=button><abbr title="See Definition"><i>i</i></abbr></button></dt>
<dd>a precious silvery-white metal, the chemical element of atomic number 78.</dd>
</dl>
Upvotes: 1
Reputation: 14191
This could be a solution. You can loop through the elements which contain the class you want to toggle, if they do, then toggle it
document.querySelectorAll("dl").forEach(dl =>
dl.addEventListener("click", ({ target }) => {
document.querySelectorAll(".open").forEach(function(element) {
if(element.classList.contains("open")){
element.classList.toggle("open");
}
});
document.querySelectorAll(".active").forEach(function(element) {
if(element.classList.contains("active")){
element.classList.toggle("active");
}
});
if (!target.matches("button")) return
target.classList.toggle("active")
target.parentElement.nextElementSibling.classList.toggle("open")
})
)
dd {
visibility: hidden;
height: 0
}
.open {
visibility: visible;
height: auto
}
.active {
color: DeepSkyBlue
}
abbr {
pointer-events: none
}
<body>
<dl>
<dt>aluminum
<button type=button><abbr title="See Definition"><i>i</i></abbr></button></dt>
<dd>the chemical element of atomic number 13, a light silvery-grey metal.</dd>
<dt>silver
<button type=button><abbr title="See Definition"><i>i</i></abbr></button></dt>
<dd>a precious shiny greyish-white metal, the chemical element of atomic number 47.</dd>
<dt>gold
<button type=button><abbr title="See Definition"><i>i</i></abbr></button></dt>
<dd>a yellow precious metal, the chemical element of atomic number 79.</dd>
<dt>platinum
<button type=button><abbr title="See Definition"><i>i</i></abbr></button></dt>
<dd>a precious silvery-white metal, the chemical element of atomic number 78.</dd>
</dl>
</body>
Upvotes: 1
Reputation: 4481
You have to hide the open option before opening the new one. You could do like this:
window.onload = function() {
document.querySelectorAll("dl").forEach(dl =>
dl.addEventListener("click", ({ target }) => {
if (!target.matches("button")) return
const dl = target.closest('dl');
// Check if there is an active button and remove active class
if (dl.querySelector('.active') != null) {
dl.querySelector('.active').classList.toggle('active');
}
// Check if there is an open dd and close it
if (dl.querySelector('.open') != null) {
dl.querySelector('.open').classList.toggle('open');
}
target.classList.toggle("active")
target.parentElement.nextElementSibling.classList.toggle("open")
})
)
}
dd {
visibility: hidden;
height: 0
}
.open {
visibility: visible;
height: auto
}
.active {
color: DeepSkyBlue
}
abbr {
pointer-events: none
}
<p>Car List.</p>
<p id="show"></p>
<p id="show1"></p>
<dl>
<dt>aluminum
<button type=button><abbr title="See Definition"><i>i</i></abbr></button></dt>
<dd>the chemical element of atomic number 13, a light silvery-grey metal.</dd>
<dt>silver
<button type=button><abbr title="See Definition"><i>i</i></abbr></button></dt>
<dd>a precious shiny greyish-white metal, the chemical element of atomic number 47.</dd>
<dt>gold
<button type=button><abbr title="See Definition"><i>i</i></abbr></button></dt>
<dd>a yellow precious metal, the chemical element of atomic number 79.</dd>
<dt>platinum
<button type=button><abbr title="See Definition"><i>i</i></abbr></button></dt>
<dd>a precious silvery-white metal, the chemical element of atomic number 78.</dd>
</dl>
Upvotes: 3