user3222157 user3222157 - 4 months ago 7
Javascript Question

keep only one li node open in tree view display

I want to hide other siblings li when i click one li to diplay tree view.
Only one node should open and its children elements have to expand. check the fiddle links below .
Html code :

  • Part 1

    • Item A

      • Sub-item 1

      • Sub-item 2

      • Sub-item 3



    • Item B

      • Sub-item 1

      • Sub-item 2

      • Sub-item 3



    • Item C

      • Sub-item 1

      • Sub-item 2

      • Sub-item 3



    • Item D

      • Sub-item 1

      • Sub-item 2

      • Sub-item 3



    • Item E

      • Sub-item 1

      • Sub-item 2

      • Sub-item 3






  • <li><a href="#">Part 2</a>
    <ul>
    <li><a href="#">Item A</a>
    <ul>
    <li><a href="#">Sub-item 1</a></li>
    <li><a href="#">Sub-item 2</a></li>
    <li><a href="#">Sub-item 3</a></li>
    </ul>
    </li>
    <li><a href="#">Item B</a>
    <ul>
    <li><a href="#">Sub-item 1</a></li>
    <li><a href="#">Sub-item 2</a></li>
    <li><a href="#">Sub-item 3</a></li>
    </ul>
    </li>
    <li><a href="#">Item C</a>
    <ul>
    <li><a href="#">Sub-item 1</a></li>
    <li><a href="#">Sub-item 2</a></li>
    <li><a href="#">Sub-item 3</a></li>
    </ul>
    </li>
    <li><a href="#">Item D</a>
    <ul>
    <li><a href="#">Sub-item 1</a></li>
    <li><a href="#">Sub-item 2</a></li>
    <li><a href="#">Sub-item 3</a></li>
    </ul>
    </li>
    <li><a href="#">Item E</a>
    <ul>
    <li><a href="#">Sub-item 1</a></li>
    <li><a href="#">Sub-item 2</a></li>
    <li><a href="#">Sub-item 3</a></li>
    </ul>
    </li>
    </ul>
    </li>

    <li><a href="#">Part 3</a>
    <ul>
    <li><a href="#">Item A</a>
    <ul>
    <li><a href="#">Sub-item 1</a></li>
    <li><a href="#">Sub-item 2</a></li>
    <li><a href="#">Sub-item 3</a></li>
    </ul>
    </li>
    <li><a href="#">Item B</a>
    <ul>
    <li><a href="#">Sub-item 1</a></li>
    <li><a href="#">Sub-item 2</a></li>
    <li><a href="#">Sub-item 3</a></li>
    </ul>
    </li>
    <li><a href="#">Item C</a>
    <ul>
    <li><a href="#">Sub-item 1</a></li>
    <li><a href="#">Sub-item 2</a></li>
    <li><a href="#">Sub-item 3</a></li>
    </ul>
    </li>
    <li><a href="#">Item D</a>
    <ul>
    <li><a href="#">Sub-item 1</a></li>
    <li><a href="#">Sub-item 2</a></li>
    <li><a href="#">Sub-item 3</a></li>
    </ul>
    </li>
    <li><a href="#">Item E</a>
    <ul>
    <li><a href="#">Sub-item 1</a></li>
    <li><a href="#">Sub-item 2</a></li>
    <li><a href="#">Sub-item 3</a></li>
    </ul>
    </li>
    </ul>
    </li>
    </ul>

    css :
    ul.tree li {
    list-style-type: none;
    position: relative;
    }

    ul.tree li ul {
    display: none;
    }

    ul.tree li.open > ul {
    display: block;
    }

    ul.tree li a {
    color: black;
    text-decoration: none;
    }

    ul.tree li a:before {
    height: 1em;
    padding:0 .1em;
    font-size: .8em;
    display: block;
    position: absolute;
    left: -1.3em;
    top: .2em;
    }

    ul.tree li > a:not(:last-child):before {
    content: '+';
    }

    ul.tree li.open > a:not(:last-child):before {
    content: '-';
    }

    js code :

    var tree = document.querySelectorAll('ul.tree a:not(:last-child)');
    for(var i = 0; i < tree.length; i++){
    tree[i].addEventListener('click', function(e) {
    var parent = e.target.parentElement;
    var classList = parent.classList;
    if(classList.contains("open")) {
    classList.remove('open');
    var opensubs = parent.querySelectorAll(':scope .open');
    for(var i = 0; i < opensubs.length; i++){
    opensubs[i].classList.remove('open');
    }
    } else {
    classList.add('open'); // Here only i want that condition to check li is already opened or not//
    }
    });
    }

    For more info : https://jsfiddle.net/te366hu2/2/

    Answer

    I have modified you js code a bit to collapse the sibling nodes. Full working fiddle here

    var tree = document.querySelectorAll('ul.tree a:not(:last-child)');
    for(var i = 0; i < tree.length; i++){
        tree[i].addEventListener('click', function(e) {
            var parent = e.target.parentElement;
            var classList = parent.classList;
            var closeAllOpenSiblings = function(){        
                var opensubs = parent.parentElement.querySelectorAll(':scope .open');
                for(var i = 0; i < opensubs.length; i++){
                    opensubs[i].classList.remove('open');
                }
            }
            if(classList.contains("open")) {
                classList.remove('open');
            } else {
                closeAllOpenSiblings();
                classList.add('open');
            }
        });
    }