Reputation: 25
With my current code I am successfully able to open/close list elements one by one by clicking on my div
element. However I would like to toggle
once more all child elements by clicking it's parent. To simplify - when I open both Level 1
and Level 2
I would like to reset their state just by clicking at Level 1
element.
Additionally it seems like my <div class="toggle-btn"></div>
element is toggling with higher delay than it's sibling. Why is that happening and how to fix it?
$(function () {
$("#collapse li").children('ul').hide();
$(".toggle-btn").on('click', function (event) {
$(this).next('ul').stop().slideToggle(150);
$(this).toggleClass('active');
event.stopPropagation();
});
});
#collapse, ul {
display:block;
list-style:none;
width: 100%;
}
#collapse li {
display: flex;
width: 100%;
flex-wrap: wrap;
}
.toggle-btn {
display: flex;
overflow: hidden;
cursor: pointer;
padding: 5px 0px 0px 20px;
}
.toggle-btn::before {
content: '';
display: flex;
position: absolute;
height: 8px;
width: 2px;
background: black;
transform: rotate(0deg);
}
.toggle-btn::after {
content: '';
display: flex;
position: absolute;
height: 8px;
width: 2px;
background: black;
transform: rotate(90deg);
}
.active::before {
content: '';
display: flex;
position: absolute;
height: 8px;
width: 2px;
background: black;
transform: rotate(90deg) !important;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul id="collapse">
<li>Level 1
<div class="toggle-btn"></div>
<ul>
<li>Level 2
<div class="toggle-btn"></div>
<ul>
<li>Level 3</li>
<li>Level 3</li>
</ul>
</li>
<li>Level 2
<div class="toggle-btn"></div>
<ul>
<li>Level 3</li>
<li>Level 3</li>
</ul>
</li>
</ul>
</li>
<li>Level 1
<div class="toggle-btn"></div>
<ul>
<li>Level 2
<div class="toggle-btn"></div>
<ul>
<li>Level 3</li>
<li>Level 3</li>
</ul>
</li>
<li>Level 2
<div class="toggle-btn"></div>
<ul>
<li>Level 3</li>
<li>Level 3</li>
</ul>
</li>
</ul>
</li>
<li>Level 1
<div class="toggle-btn"></div>
<ul>
<li>Level 2
<div class="toggle-btn"></div>
<ul>
<li>Level 3</li>
<li>Level 3</li>
</ul>
</li>
<li>Level 2
<div class="toggle-btn"></div>
<ul>
<li>Level 3</li>
<li>Level 3</li>
</ul>
</li>
</ul>
</li>
</ul>
Additionally it seems like my <div class="toggle-btn"></div>
Upvotes: 1
Views: 60
Reputation: 1063
Here's the solution I came up with:
$(function () {
$("#collapse li").children('ul').hide();
$(".toggle-btn").on('click', function (event) {
$(this).next('ul').stop().slideToggle(150);
if ($(this).hasClass('active')){
let subActive = $(this).parent().find(".active").slice(1);
$(subActive).each(function() {
$(this).toggleClass('active');
$(this).next('ul').stop().slideToggle(150);
});
}
$(this).toggleClass('active');
event.stopPropagation();
});
});
https://jsfiddle.net/dp7148u2/
Upvotes: 1
Reputation: 3519
First of all, if this is for a project, please consider using a library such as FancyTree. These libraries are very efficient and offer a ton of customization options.
Here is a solution. I added a new attribute to all the <div>
s to have them save their state.
<div class="toggle-btn" data-div="close"></div>
Then I had the event handler look at this attribute and reset the state of closed leaves based on it. Here is the original snippet with the changes made:
$(function () {
$("#collapse li").children('ul').hide();
$(".toggle-btn").on('click', function (event) {
let div = $(this);
let list = div.next('ul');
list.stop().slideToggle(150);
div.toggleClass('active');
if(div.attr("data-div") === "open") {
list.find('ul').hide();
list.find('div').removeClass('active');
list.find('div').attr("data-div", "close");
}
div.attr("data-div", "open")
event.stopPropagation();
});
});
#collapse, ul {
display:block;
list-style:none;
width: 100%;
}
#collapse li {
display: flex;
width: 100%;
flex-wrap: wrap;
}
.toggle-btn {
display: flex;
overflow: hidden;
cursor: pointer;
padding: 5px 0px 0px 20px;
}
.toggle-btn::before {
content: '';
display: flex;
position: absolute;
height: 8px;
width: 2px;
background: black;
transform: rotate(0deg);
}
.toggle-btn::after {
content: '';
display: flex;
position: absolute;
height: 8px;
width: 2px;
background: black;
transform: rotate(90deg);
}
.active::before {
content: '';
display: flex;
position: absolute;
height: 8px;
width: 2px;
background: black;
transform: rotate(90deg) !important;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul id="collapse">
<li>Level 1
<div class="toggle-btn" data-div="close"></div>
<ul>
<li>Level 2
<div class="toggle-btn" data-div="close"></div>
<ul>
<li>Level 3</li>
<li>Level 3</li>
</ul>
</li>
<li>Level 2
<div class="toggle-btn" data-div="close"></div>
<ul>
<li>Level 3</li>
<li>Level 3</li>
</ul>
</li>
</ul>
</li>
<li>Level 1
<div class="toggle-btn" data-div="close"></div>
<ul>
<li>Level 2
<div class="toggle-btn" data-div="close"></div>
<ul>
<li>Level 3</li>
<li>Level 3</li>
</ul>
</li>
<li>Level 2
<div class="toggle-btn" data-div="close"></div>
<ul>
<li>Level 3</li>
<li>Level 3</li>
</ul>
</li>
</ul>
</li>
<li>Level 1
<div class="toggle-btn" data-div="close"></div>
<ul>
<li>Level 2
<div class="toggle-btn" data-div="close"></div>
<ul>
<li>Level 3</li>
<li>Level 3</li>
</ul>
</li>
<li>Level 2
<div class="toggle-btn" data-div="close"></div>
<ul>
<li>Level 3
<div class="toggle-btn" data-div="close"></div>
<ul>
<li>Level 4</li>
<li>Level 4</li>
</ul>
</li>
<li>Level 3</li>
</ul>
</li>
</ul>
</li>
</ul>
Upvotes: 1