0

I am retrieving data via JSON from a database, so the data is subject to change constantly; I can't hard-code the JSON. Here is some sample JSON to illustrate this example:

[{"Building":"18A","Room":219,"Location":"E-4-6","BarCode":"P000019152"}, 
 {"Building":"18G","Room":"112HALL","Location":"J-8-5","BarCode":"P000031111"}, 
 {"Building":"18G","Room":"112HALL","Location":"J-8-5","BarCode":"P166279435"}, 
 {"Building":"18G","Room":"112HALL","Location":"A-10-7","BarCode":"P352831849"}, 
 {"Building":"18G","Room":"5P04","Location":"C-4-10","BarCode":"P726526379"}, 
 {"Building":"18C","Room":"6THST","Location":"CAGE14","BarCode":"P000453262"}, 
 {"Building":"18C","Room":"6THST","Location":"CAGE13","BarCode":"P954732810"}]

What I need to do is parse this array and create a tree view out of it. From above, the tree view would look like this:

>18A
  >219
    >E-4-6
       >P000019152
>18G
  >112HALL
    >J-8-5
       >P000019152
       >P166279435
    >A-10-7
       >P166279435
  >5P04
    >C-4-10
       >P726526379
>18C
  >6THST
     >CAGE14
        >P000453262
     >CAGE13
        >P954732810

The important thing to note is my JSON is not structured in a way that there are parent and child objects; in other words, it is not nested. Is there any way I can parse this JSON string and create a logical and hierarchical tree view out of it, based on the order of building, room, location, then bar code?

What I've tried so far:

 var input=[{"Building":"18A","Room":"219","Location":"E-4-6","BarCode":"P000019152"}, 
 {"Building":"18G","Room":"112HALL","Location":"J-8-5","BarCode":"P000031111"}, 
 {"Building":"18G","Room":"112HALL","Location":"J-8-5","BarCode":"P166279435"}, 
 {"Building":"18G","Room":"112HALL","Location":"A-10-7","BarCode":"P352831849"}, 
 {"Building":"18G","Room":"5P04","Location":"C-4-10","BarCode":"P726526379"}, 
 {"Building":"18C","Room":"6THST","Location":"CAGE14","BarCode":"P000453262"},
 {"Building":"18C","Room":"6THST","Location":"C1","BarCode":"P954732810"}];

function ToNestedObject(input){
    var i, y, len = input.length, parts, partsLen, obj = {}, prev;
    for(i = 0; i < len; i++){
        parts = input[i]; 
        partsLen = parts.length;
        prev = obj; 
        for(y = 0; y < partsLen; y++){
            prev[parts[y]] = prev[parts[y]] || {};    
            prev = prev[parts[y]];
        }
        if(!prev.ids){
            prev.ids = []; 
        }
        prev.ids.push(input[i].id); 
    }
    return obj; 
}

function ToHTML(input){
    var html = '<ul>'; 

    for(var key in input){
        if(input[key] instanceof Array){
            for(var i = 0; i < input[key].length; i++){
                html += '<li>' + input[key][i] + '</li>';
            }
        } else {
            html += '<li>' + key + ToHTML(input[key]) + '</li>';
        }           
    }
    html += '</ul>';
    return html; 
}
document.getElementById('test').innerHTML = ToHTML(ToNestedObject(input)); 
6
  • 2
    If you're fine with the nesting being implemented with nested ul elements, this is very simple to do. What difficulty are you having doing this yourself? Commented Jan 6, 2020 at 18:18
  • Use JSON.parse to convert the string into a JS Array and then build a new Object from that Array which matches the structure you want. Finally convert that Object to HTML. I can provide a more detailed answer if you need one. Commented Jan 6, 2020 at 18:20
  • @Taplar Thank you for your response. I'm sure it is simple to some degree, but I'm pretty new to working with JSON in JavaScript. Commented Jan 6, 2020 at 18:23
  • 1
    @Snapstromegon An answer would definitely be helpful. Commented Jan 6, 2020 at 18:24
  • 1
    @MaxVoisard typically answers are provided for questions that have demonstrated an effort has been made. So far your question has not done that. meta.stackoverflow.com/questions/261592/… How to Ask Commented Jan 6, 2020 at 18:27

2 Answers 2

3

You could first create nested structure using recursion and the from that data create html with ul and li elements.

const data = [{"Building":"18A","Room":219,"Location":"E-4-6","BarCode":"P000019152"}, 
 {"Building":"18G","Room":"112HALL","Location":"J-8-5","BarCode":"P000031111"}, 
 {"Building":"18G","Room":"112HALL","Location":"J-8-5","BarCode":"P166279435"}, 
 {"Building":"18G","Room":"112HALL","Location":"A-10-7","BarCode":"P352831849"}, 
 {"Building":"18G","Room":"5P04","Location":"C-4-10","BarCode":"P726526379"}, 
 {"Building":"18C","Room":"6THST","Location":"CAGE14","BarCode":"P000453262"}, 
 {"Building":"18C","Room":"6THST","Location":"CAGE13","BarCode":"P954732810"}]
const order = ['Building', 'Room', 'Location', 'BarCode'];

function nest(data, keys) {
  return data.reduce((result, e) => {
    keys.reduce((r, k, a, i) => {
      return r[e[k]] = (r[e[k]] || {})
    }, result)

    return result;
  }, {})
}

function toHtml(data, parent) {
  const ul = document.createElement('ul');
  Object.keys(data).forEach(key => {
    const li = document.createElement('li');
    li.textContent = key;
    li.appendChild(toHtml(data[key], li))
    ul.appendChild(li)
  })
  return ul;
}

const result = nest(data, order);
const html = toHtml(result);

document.body.appendChild(html)

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

1 Comment

Thanks a lot. The front-end looks a lot better using jsTree, in which you could append the child to <div id="tree"></div> by using document.getElementById("tree").appendChild(html); and then simply $('#tree').jstree();. That's what I did from your answer.
1

To get you started, you can use iterate through the array and hierarchy of keys to convert the array of objects into a nested hierarchy of objects. Here's a 1-liner:

let values = [
  {
    "Building": "18A",
    "Room": 219,
    "Location": "E-4-6",
    "BarCode": "P000019152"
  },
  {
    "Building": "18G",
    "Room": "112HALL",
    "Location": "J-8-5",
    "BarCode": "P000031111"
  },
  {
    "Building": "18G",
    "Room": "112HALL",
    "Location": "J-8-5",
    "BarCode": "P166279435"
  },
  {
    "Building": "18G",
    "Room": "112HALL",
    "Location": "A-10-7",
    "BarCode": "P352831849"
  },
  {
    "Building": "18G",
    "Room": "5P04",
    "Location": "C-4-10",
    "BarCode": "P726526379"
  },
  {
    "Building": "18C",
    "Room": "6THST",
    "Location": "CAGE14",
    "BarCode": "P000453262"
  },
  {
    "Building": "18C",
    "Room": "6THST",
    "Location": "CAGE13",
    "BarCode": "P954732810"
  }];

let hierarchy = ['Building', 'Room', 'Location', 'BarCode'];

let output = {};
values.forEach(v => hierarchy.reduce((o, h) => o[v[h]] = o[v[h]] || {}, output));

console.log(output);

Comments

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.