skip to Main Content

I have a tree view based on this https://www.w3schools.com/howto/howto_js_treeview.asp

It has several layers of nodes. Users have said they would like a button to expand the whole tree view (all the nodes, all the way down) in a single action.

How can I do this?

I’m afraid I know very little about Javascript (I’m a Python programmer and I’m generating all the HTML, CSS and JS from Python). In JS not sure if I can query for all nested nodes and then open them. Or if I should recurse in some way.

This is Javascript which opens a single node:

var toggler = document.getElementsByClassName("caret");
var i;

for (i = 0; i < toggler.length; i++) {
  toggler[i].addEventListener("click", function() {
    this.parentElement.querySelector(".nested").classList.toggle("active");
    this.classList.toggle("caret-down");
  });
} 
/* Remove default bullets */
ul, #myUL {
  list-style-type: none;
}

/* Remove margins and padding from the parent ul */
#myUL {
  margin: 0;
  padding: 0;
}

/* Style the caret/arrow */
.caret {
  cursor: pointer;
  user-select: none; /* Prevent text selection */
}

/* Create the caret/arrow with a unicode, and style it */
.caret::before {
  content: "25B6";
  color: black;
  display: inline-block;
  margin-right: 6px;
}

/* Rotate the caret/arrow icon when clicked on (using JavaScript) */
.caret-down::before {
  transform: rotate(90deg);
}

/* Hide the nested list */
.nested {
  display: none;
}

/* Show the nested list when the user clicks on the caret/arrow (with JavaScript) */
.active {
  display: block;
} 
<ul id="myUL">
  <li><span class="caret">Beverages</span>
    <ul class="nested">
      <li>Water</li>
      <li>Coffee</li>
      <li><span class="caret">Tea</span>
        <ul class="nested">
          <li>Black Tea</li>
          <li>White Tea</li>
          <li><span class="caret">Green Tea</span>
            <ul class="nested">
              <li>Sencha</li>
              <li>Gyokuro</li>
              <li>Matcha</li>
              <li>Pi Lo Chun</li>
            </ul>
          </li>
        </ul>
      </li>
    </ul>
  </li>
</ul> 

2

Answers


  1. The simplest way would be to update the .nested class in the CSS, either remove it, replace it or change the styling

    Something like

    document.getElementsByClassName("nested").style.display="block";
    

    Should do the trick, not the best solution but you should get the general idea.

    You could also

    • add your active class to all .nested in a similar fashion
    • use a third class for targeting and remove all .nested on a toggle
    • use a CSS variable for the display value on .nested and update that (probably what I’d do)
    • use JQuery (like it’s still 15 years ago) and $(‘.nested’).show();

    See this question for more details : How to change CSS property using JavaScript

    Login or Signup to reply.
  2. It’s actually simpler than before, just need to use forEach function to toggle class.

    Edit:

    I add nest.every(d => !d.classList.contains('active')) to check if the tree was opened.

    const toggler = [...document.getElementsByClassName("caret")];
    const nest = [...document.querySelectorAll(".nested")]
    const expandAll = document.getElementById("expand-all")
    toggler.forEach(d => d.addEventListener('click', e => {
      e.target.parentElement.querySelector(".nested").classList.toggle("active");
      e.target.classList.toggle("caret-down");
    }))
    
    expandAll.addEventListener('click', () => {
      if (nest.every(d => !d.classList.contains('active'))) {
        toggler.forEach(t => t.classList.add('caret-down'))
        nest.forEach(n => n.classList.add('active'))
      } else {
        toggler.forEach(t => t.classList.remove('caret-down'))
        nest.forEach(n => n.classList.remove('active'))
      }
    })
    /* Remove default bullets */
    
    ul,
    #myUL {
      list-style-type: none;
    }
    
    
    /* Remove margins and padding from the parent ul */
    
    #myUL {
      margin: 0;
      padding: 0;
    }
    
    
    /* Style the caret/arrow */
    
    .caret {
      cursor: pointer;
      user-select: none;
      /* Prevent text selection */
    }
    
    
    /* Create the caret/arrow with a unicode, and style it */
    
    .caret::before {
      content: "25B6";
      color: black;
      display: inline-block;
      margin-right: 6px;
    }
    
    
    /* Rotate the caret/arrow icon when clicked on (using JavaScript) */
    
    .caret-down::before {
      transform: rotate(90deg);
    }
    
    
    /* Hide the nested list */
    
    .nested {
      display: none;
    }
    
    
    /* Show the nested list when the user clicks on the caret/arrow (with JavaScript) */
    
    .active {
      display: block;
    }
    <button id="expand-all">expand all</button>
    <ul id="myUL">
      <li><span class="caret">Beverages</span>
        <ul class="nested">
          <li>Water</li>
          <li>Coffee</li>
          <li><span class="caret">Tea</span>
            <ul class="nested">
              <li>Black Tea</li>
              <li>White Tea</li>
              <li><span class="caret">Green Tea</span>
                <ul class="nested">
                  <li>Sencha</li>
                  <li>Gyokuro</li>
                  <li>Matcha</li>
                  <li>Pi Lo Chun</li>
                </ul>
              </li>
            </ul>
          </li>
        </ul>
      </li>
    </ul>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search