skip to Main Content
document.addEventListener("DOMContentLoaded", function () {
    const jsonData = [
        { text: "TITLE 1", children: [
                { text: "subtitle 1",  children: [
                        { text: "sub subtitle 1a" },
                        { text: "sub subtitle 1b" } ] }, 
                { text: "subtitle 2", children: [
                        { text: "sub subtitle 2a"},
                        { text: "sub subtitle 2b"}
                ] },
                { text: "subtitle 3" }
            ] },
        { text: "TITLE 2", children: [
                { text: "subtitle 1" },
                { text: "subtitle 2" },
                { text: "subtitle 3" } ] },
        { text: "TITLE 3", children: [
                { text: "subtitle 1", children: [
                        { text: "sub subtitle 1a" },
                        { text: "sub subtitle 1b" } ] },
                { text: "subtitle 2" }
            ]
        }
    ];

    const treeContainer = document.getElementById("tree");

    function createTree(treeData, parentElement) {
        treeData.forEach(item => {
            const listItem = document.createElement("li");
            const toggleButton = document.createElement("button");
            toggleButton.innerText = item.text;

            let sublist; // Define sublist variable here

            if (item.children) { // still have children
                sublist = document.createElement("ul");
                
                
                // toggleButton.style.content = "▼";
                createTree(item.children, sublist);
                listItem.appendChild(toggleButton);
                listItem.appendChild(sublist);
            } else { // no more children
                const toggleButton2 = document.createElement("button");
                toggleButton2.innerText = item.text;
                listItem.appendChild(toggleButton2);
            }

            toggleButton.addEventListener("click", () => {
                if (sublist) {
                    toggleButton.classList.toggle("toggled");
                    
                        if(sublist.style.maxHeight){
                            sublist.style.maxHeight = null;
                        } else {

                sublist.style.maxHeight = sublist.scrollHeight + "px";
                           

                        }
                 
                }
               

            });

            

            parentElement.appendChild(listItem);
        });
    }

    createTree(jsonData, treeContainer);
});
/* Apply basic styling */
ul {
    list-style-type: none;
    padding-left: 20px;
    margin: 0px;
    overflow: hidden;
    max-height: 0;
    transition: max-height 0.2s ease-out;
    
}

li {
    list-style-type: none;
    padding-left: 20px;
    margin: 0px;
}

li > button {
    background: blue;
    border: none;
    border-radius: 3px;
    cursor: pointer;
    padding: 10px;
   
}


  
li > ul > li > button {
    background: yellow;
    border: none;
    cursor: pointer;
    padding: 10px;
}

li > ul > li > ul > li > button {
    background: green;
    border: none;
    cursor: pointer;
    padding: 0;
}


button:focus {
    outline: none;
}

/* Add icon for the toggle button */
button:has(+ ul)::after {
    content: "25BC";
    padding-right: 5px;
}

/* Style the button when it's toggled */
button.toggled:has(+ ul)::after {
    content: "25B2";
  }
<!DOCTYPE html>
<html>
<head>
  <title>My Site  </title>
  <link rel="stylesheet" href="style.css">

  <meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>



  <div id="tree"></div>
  <script src="script.js"></script>


</body>
</html>

I have the html ,css js codes as above.

enter image description here

when i click the title 1, it expands using the maxheight attributes

enter image description here

when i click the subtitle 1, it still expand its content but the subtitle 3 is being cut out from the view.

how to make the subtitle 3 still in view after expanding subtitle 1, etc

ive tried chatgpt / bard, but no use.

2

Answers


  1. You can simply adjust the maxHeight with the calc function

    sublist.style.maxHeight = `calc(100% - 100px)`

    Here’s a working Demo:

    document.addEventListener("DOMContentLoaded", function () {
        const jsonData = [
            { text: "TITLE 1", children: [
                    { text: "subtitle 1",  children: [
                            { text: "sub subtitle 1a" },
                            { text: "sub subtitle 1b" } ] }, 
                    { text: "subtitle 2", children: [
                            { text: "sub subtitle 2a"},
                            { text: "sub subtitle 2b"}
                    ] },
                    { text: "subtitle 3"}
                ] },
            { text: "TITLE 2", children: [
                    { text: "subtitle 1" },
                    { text: "subtitle 2" },
                    { text: "subtitle 3" } ] },
            { text: "TITLE 3", children: [
                    { text: "subtitle 1", children: [
                            { text: "sub subtitle 3a" },
                            { text: "sub subtitle 3b" } ] },
                    { text: "subtitle 2" }
                ]
            }
        ];
    
        const treeContainer = document.getElementById("tree");
    
        function createTree(treeData, parentElement) {
            treeData.forEach(item => {
                const listItem = document.createElement("li");
                const toggleButton = document.createElement("button");
                toggleButton.innerText = item.text;
    
                let sublist; // Define sublist variable here
    
                if (item.children) { // still have children
                    sublist = document.createElement("ul");
                    
                    
                    // toggleButton.style.content = "▼";
                    createTree(item.children, sublist);
                    listItem.appendChild(toggleButton);
                    listItem.appendChild(sublist);
                } else { // no more children
                    const toggleButton2 = document.createElement("button");
                    toggleButton2.innerText = item.text;
                    listItem.appendChild(toggleButton2);
                }
    
                toggleButton.addEventListener("click", () => {
                   
                    if (sublist) {
                        toggleButton.classList.toggle("toggled");
                        
                            if(sublist.style.maxHeight){
                                sublist.style.maxHeight = null;
                            } else {     
                              sublist.style.maxHeight = `calc(100% - 100px)`  
                            }
                    }
                   
    
                });
    
                
    
                parentElement.appendChild(listItem);
            });
        }
    
        createTree(jsonData, treeContainer);
    });
        /* Apply basic styling */
    ul {
        list-style-type: none;
        padding-left: 20px;
        margin: 0px;
        overflow: hidden;
        max-height: 0;
        transition: max-height 0.2s ease-out;
        
    }
    
    li {
        list-style-type: none;
        padding-left: 20px;
        margin: 0px;
    }
    
    li > button {
        background: blue;
        border: none;
        border-radius: 3px;
        cursor: pointer;
        padding: 10px;
       
    }
    
    
      
    li > ul > li > button {
        background: yellow;
        border: none;
        cursor: pointer;
        padding: 10px;
    }
    
    li > ul > li > ul > li > button {
        background: green;
        border: none;
        cursor: pointer;
        padding: 0;
    }
    
    
    button:focus {
        outline: none;
    }
    
    /* Add icon for the toggle button */
    button:has(+ ul)::after {
        content: "25BC";
        padding-right: 5px;
    }
    
    /* Style the button when it's toggled */
    button.toggled:has(+ ul)::after {
        content: "25B2";
      }
      <div id="tree"></div>
    Login or Signup to reply.
  2. You need to take into account the scroll height of the sublist’s child nodes, as well as the scroll height of the toggle button. So, you have to change the line:

    sublist.style.maxHeight = sublist.scrollHeight + "px";
    

    with the following:

    let childLength = sublist.childNodes.length;
    let childNodeHeight = sublist.childNodes[0].scrollHeight;
    sublist.style.maxHeight = (sublist.scrollHeight + toggleButton.scrollHeight + (childLength * childNodeHeight)) + "px"; 
    

    You can test the result here.

    Try adding more list items to a sublist to test if it’s responding correctly.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search