Auto-close similar childs

I have this code.
document.querySelectorAll('.button-collapse').forEach(button => {
button.addEventListener("click", () => {
const collapseBox = button.nextElementSibling;

button.classList.toggle('active-btn');
collapseBox.classList.toggle('active');
});
});
document.querySelectorAll('.button-collapse').forEach(button => {
button.addEventListener("click", () => {
const collapseBox = button.nextElementSibling;

button.classList.toggle('active-btn');
collapseBox.classList.toggle('active');
});
});
Basically a collapsible box. I wanted to make it so, whenever a different one gets opened, collapses the last one, but haven't been able to wrap my head around it. Tried some if statements, but can't quite find the logic. Is there a way to make that? If anyone is curious, it's right here: https://cozynova.online/windcutter/#New-Player
Wind Cutter Guide
Comprehensive, concise and dynamic Ragnarok Online guide.
13 Replies
croganm
croganm•2y ago
So when you open one box, you want to close all the other boxes?
Myndi
Myndi•2y ago
Yeah, to maintain one opened at the time, essentially.
croganm
croganm•2y ago
Well the first thing I would do is make sure none of the elements have the active class on them. That means removing it from the box that is active. Then, after that, I would do what you're doing which is adding the active class to the one that's clicked
Myndi
Myndi•2y ago
But that's exactly what is happening right confusedDog
croganm
croganm•2y ago
You're only toggling the one that is clicked. You're not toggling the ones that are already active
Myndi
Myndi•2y ago
So you mean something like, "if a sibling has active statement, remove it"? I mean, tried to do that, but couldn't wrap my head around the logic behind it. That's why I made the post here. Or perhaps, couldn't make it work.
croganm
croganm•2y ago
Just query select all active elements and remove the active class Then keep what you're currently doing
Myndi
Myndi•2y ago
I will give it a try in the morning, mayhaps I just overcomplicated things.
croganm
croganm•2y ago
Haha sleep usually solves all coding problems. I promise, don't overcomplicate it. Just select all buttons and boxes with active class, loop over them and remove the class. Then, take the button and box you just clicked and add the class. I would provide the code but you'll learn it better once you do it, I promise 😂 Just breakdown the problem one by one. Do it in order and you'll get the solution
Myndi
Myndi•2y ago
const activeBoxes = document.querySelectorAll('.active').forEach(button => {
button.addEventListener("click", () => {

if(activeBoxes.classList === 'active'){
activeBoxes.classList.remove('active');
}
});
});

document.querySelectorAll('.button-collapse').forEach(button => {
button.addEventListener("click", (e) => {
const collapseBox = button.nextElementSibling;

button.classList.toggle('active-btn');
collapseBox.classList.toggle('active');
});
});
const activeBoxes = document.querySelectorAll('.active').forEach(button => {
button.addEventListener("click", () => {

if(activeBoxes.classList === 'active'){
activeBoxes.classList.remove('active');
}
});
});

document.querySelectorAll('.button-collapse').forEach(button => {
button.addEventListener("click", (e) => {
const collapseBox = button.nextElementSibling;

button.classList.toggle('active-btn');
collapseBox.classList.toggle('active');
});
});
I thought I had it here, but ... no 😔 Then I thought of document.activeElement but couldn't quite wrap the logic around it. This is working for me now, but I just gave up trying to remove the active state from the button. How can I link them together?
document.querySelectorAll(".button-collapse").forEach((button) => {
button.addEventListener("click", (e) => {
const collapseBox = button.nextElementSibling;

var i;
const array = document.querySelectorAll(".active");
for (i = 0; i < array.length; i++) {
if (collapseBox.nextElementSibling != array[i])
array[i].classList.toggle("active");
}

button.classList.toggle("active-btn");
collapseBox.classList.toggle("active");
});
});
document.querySelectorAll(".button-collapse").forEach((button) => {
button.addEventListener("click", (e) => {
const collapseBox = button.nextElementSibling;

var i;
const array = document.querySelectorAll(".active");
for (i = 0; i < array.length; i++) {
if (collapseBox.nextElementSibling != array[i])
array[i].classList.toggle("active");
}

button.classList.toggle("active-btn");
collapseBox.classList.toggle("active");
});
});
croganm
croganm•2y ago
All you want to do is
document.querySelectorAll('.active').forEach(el => el.classList.remove('active')
document.querySelectorAll('.active').forEach(el => el.classList.remove('active')
That removes all the active classes Make that the very first thing after the button click Just select all active elements, loop over them, and remove it ^ You may want to do something similar for the button as well
document.querySelectorAll('.active-btn').forEach(el => el.classList.remove('active-btn')
document.querySelectorAll('.active-btn').forEach(el => el.classList.remove('active-btn')
Myndi
Myndi•2y ago
I guess that's just simpler. Iterating over an element didn't cross my mind. Thank you for the function.
croganm
croganm•2y ago
Haha no worries, sometimes we need to go back to the basics