iamrobin.
iamrobin.

Reputation: 1634

generate elements based on key structure of object

I have an multidimensional object. Now I wanna generate DOM-elements based on the key structure of this object.

As a default view all root keys should be shown as div elements. With a click on one of this elements the divs should be replaced with the direct children of the clicked key.

My current version looks like this

object:

let object = {
    "1.0": {
        "1.0.1": {},
        "1.0.2": {},
    },
    "1.1": {
        "1.1.1": {
            "1.1.1.1": {},
        },
        "1.1.2": {},
    },   
};

this is my recursive function to generate DOM elements for each key:

function categoryTree(obj) {
    for (var key in obj) {
        categoryContainer.innerHTML += "<div>" + key + "</div>";
        categoryTree(obj[key]);
    }
}

Now, I don't know how to make this interactive and show the child keys only when the parent was clicked.

Upvotes: 0

Views: 45

Answers (2)

Nenad Vracar
Nenad Vracar

Reputation: 122047

You could build nested html structure with createElement and for...in loop. And then you can also add event listener on div that will toggle its children display property.

let object = {
  "1.0": {
    "1.0.1": {},
    "1.0.2": {}
  },
  "1.1": {
    "1.1.1": {
      "1.1.1.1": {}
    },
    "1.1.2": {}
  }
}

let categoryContainer = document.querySelector(".categoryContainer")

function categoryTree(obj, parent, start = true) {
  for (var key in obj) {
    let div = document.createElement("div");
    div.textContent = key;
    if (parent.children) parent.className += " bold";
    if (!start) div.className = "normal hide"

    div.addEventListener('click', function(e) {
      e.stopPropagation()
      Array.from(div.children).forEach(child => {
        child.classList.toggle('hide')
      })
    })
    categoryTree(obj[key], div, false)
    parent.appendChild(div)
  }
}


categoryTree(object, categoryContainer)
.hide {display: none;}
.normal {font-weight: normal;}
.bold {font-weight: bold;}
<div class="categoryContainer"></div>

Upvotes: 1

Jonas Wilms
Jonas Wilms

Reputation: 138277

Just use the DOM methods:

const n = (type, settings = {}) => Object.assign(document.createElement(type), settings);

function treeNode(name, children) {
  const text = n("p", { textContent: name });

  const container = n("div");
  container.style.display = "none";
  for(const [childName, child] of Object.entries(children))
    container.appendChild(treeNode(childName, child));

  const node = n("div");
  node.appendChild(text);
  node.appendChild(container);

  node.onclick = () => container.style.display = "block";

  return node;
}

categoryContainer.appendChild(treeNode("root", object));

Upvotes: 1

Related Questions