nivi
nivi

Reputation: 25

How to fold whole list by closing the highest element?

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

Answers (2)

Joe Fitzsimmons
Joe Fitzsimmons

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

jrook
jrook

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

Related Questions