1

trying to parse a JSON in format below to get Parent - Child tree recursively and will be processed to display a clickable list in HTML

Expected result in HTML

    var data = [
   {
      "name":"Level 1",
      "sys_id":"3b8a6ea81bd034d0d1dcb9118b4bcb9a",
      "order":"01"
   },
   {
      "name":"L1-1",
      "sys_id":"565b226c1bd034d0d1dcb9118b4bcbb2",
      "order":"01.01"
   },
   {
      "name":"Level 2",
      "sys_id":"ca49eea01bd034d0d1dcb9118b4bcb17",
      "order":"02"
   },
   {
      "name":"L2-2",
      "sys_id":"e699e2641bd034d0d1dcb9118b4bcb84",
      "order":"02.02"
   },
   {
      "name":"L2-2-1",
      "sys_id":"15da66e81bd034d0d1dcb9118b4bcb1c",
      "order":"02.02.01"
   },
   {
      "name":"L2-2-1-1",
      "sys_id":"5a2baa2c1bd034d0d1dcb9118b4bcb63",
      "order":"02.02.01.01"
   }
];

Current function for now is:

function createTreeView(data) {
  var tree = [],
    object = {},
    parent,
    child;

  for (var i = 0; i < data.length; i++) {
    parent = data[i];

    object[parent.id] = parent;
    object[parent.id]["children"] = [];
  }

  for (var id in object) {
    if (object.hasOwnProperty(id)) {
      child = object[id];      
      if (child.parentId && object[child["parentId"]]) {
        object[child["parentId"]]["children"].push(child);
      } else {
        tree.push(child);
      }
    }
  }
  return tree;
}

May I get help from you how to correctly display list based on order from JSON? Thanks a lot.

3
  • What is your expected output? What is your current output? Commented May 20, 2021 at 13:40
  • Expected output is function to parse the current JSON and display it in HTML. Currently have: function CreateUlTreeView(items, parent){ var ul = document.createElement("ul"); if (parent) parent.appendChild(ul); items.forEach(function(x) { var li = document.createElement("li"); var text = document.createElement("span"); text.innerHTML = x.name; li.appendChild(text); if (x.children && x.children.length>0) CreateUlTreeView(x.children, li); ul.append(li); }); return ul; } var root = createTreeView(locations); Commented May 20, 2021 at 13:59
  • 3
    Please update the question to include a sample of the HTML output you are trying to achieve. As well as the current HTML output you are currently getting. Commented May 20, 2021 at 14:16

2 Answers 2

2

You should prepare the data with the parent order. In case you can't do it on back end, you still can calculate it on the fly. Than just use simple recursive function to render the tree.

Here is pure JavaScript example

const data = [
   {
      "name":"Level 1",
      "sys_id":"3b8a6ea81bd034d0d1dcb9118b4bcb9a",
      "order":"01"
   },
   {
      "name":"L1-1",
      "sys_id":"565b226c1bd034d0d1dcb9118b4bcbb2",
      "order":"01.01"
   },
   {
      "name":"Level 2",
      "sys_id":"ca49eea01bd034d0d1dcb9118b4bcb17",
      "order":"02"
   },
   {
      "name":"L2-2",
      "sys_id":"e699e2641bd034d0d1dcb9118b4bcb84",
      "order":"02.02"
   },
   {
      "name":"L2-2-1",
      "sys_id":"15da66e81bd034d0d1dcb9118b4bcb1c",
      "order":"02.02.01"
   },
   {
      "name":"L2-2-1-1",
      "sys_id":"5a2baa2c1bd034d0d1dcb9118b4bcb63",
      "order":"02.02.01.01"
   }
];

function createTree(data) {
  const nodeWithParent = []
  
  // Find the parent for each node
  data.forEach(d => {
    const parent = d.order.includes('.')?d.order.substr(0, d.order.lastIndexOf('.')):null
    nodeWithParent.push({...d, parent})
  })
  
  // Recursive function to create HTML out of node
  function getNodeHtml(n) {
    const children = nodeWithParent.filter(d => d.parent === n.order)
    let html = '<li>' + n.name 
    if(children.length>0) {
      html += '<ul>' 
        + children.map(getNodeHtml).join('')
        + '</ul>'
    }
    html += '</li>'
    return html
  }
  
  // Get all root nodes (without parent)
  const root = nodeWithParent.filter(d => d.parent === null)
  
  return root.map(getNodeHtml).join('')
}

const html = createTree(data)
document.getElementById('tree').innerHTML = html
<div id="tree"></div>

Sign up to request clarification or add additional context in comments.

Comments

2

I modified Oleg's solution to include the collapsible tree behavior you were looking for.  It uses this basic example from w3schools with a little extra formatting to add the boxed plus and minus symbols:

const data = [
   {
      "name":"Level 1",
      "sys_id":"3b8a6ea81bd034d0d1dcb9118b4bcb9a",
      "order":"01"
   },
   {
      "name":"L1-1",
      "sys_id":"565b226c1bd034d0d1dcb9118b4bcbb2",
      "order":"01.01"
   },
   {
      "name":"Level 2",
      "sys_id":"ca49eea01bd034d0d1dcb9118b4bcb17",
      "order":"02"
   },
   {
      "name":"L2-2",
      "sys_id":"e699e2641bd034d0d1dcb9118b4bcb84",
      "order":"02.02"
   },
   {
      "name":"L2-2-1",
      "sys_id":"15da66e81bd034d0d1dcb9118b4bcb1c",
      "order":"02.02.01"
   },
   {
      "name":"L2-2-1-1",
      "sys_id":"5a2baa2c1bd034d0d1dcb9118b4bcb63",
      "order":"02.02.01.01"
   }
];

function createTree(data) {
  const nodeWithParent = []
  
  // Find the parent for each node
  data.forEach(d => {
    const parent = d.order.includes('.')?d.order.substr(0, d.order.lastIndexOf('.')):null
    nodeWithParent.push({...d, parent})
  })
  
  // Recursive function to create HTML out of node
  function getNodeHtml(n) {
    const children = nodeWithParent.filter(d => d.parent === n.order)
    let html = '<li><span class="box">' + n.name + '</span><ul class="nested">'
    if(children.length>0) {
      html += '<li>' 
        + children.map(getNodeHtml).join('')
        + '</li>'
    }
    html += '</ul></li>'
    return html
  }
  
  // Get all root nodes (without parent)
  const root = nodeWithParent.filter(d => d.parent === null)
  
  return root.map(getNodeHtml).join('')
}

const html = createTree(data)
let tree = document.getElementById('tree');
tree.innerHTML = html
console.log(tree)

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

for (i = 0; i < toggler.length; i++) {
  toggler[i].addEventListener("click", function() {
    console.log(this.parentElement)
    this.parentElement.querySelector(".nested").classList.toggle("active");
    this.classList.toggle("check-box");
  });
}
console.log(toggler)
ul, #tree {
  list-style-type: none;
}

li, #tree {
  font-size: 20px;
}

.box {
  cursor: pointer;
  -webkit-user-select: none; /* Safari 3.1+ */
  -moz-user-select: none; /* Firefox 2+ */
  -ms-user-select: none; /* IE 10+ */
  user-select: none;
  padding: 0px 0px;
  display: flex;
  align-items: center;
}

.box::before {
  font-size: 10px;
  font-family: "Courier New", monospace;
  content: "+";
  width: 10px;
  height: 10px;
  text-align: center;
  vertical-align: center;
  display: inline-block;
  border-style: solid;
  border-width: 1pt;
  margin-right: 5px;
}

.check-box::before {
  content: "-"; 
}

.nested {
  display: none;
}

.active {
  display: block;
}
<ul id="tree"></ul>

1 Comment

Thanks a lot! Any way how to change the + sign to - sign of the last child if entire tree was expanded?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.