简体   繁体   中英

Create an unordered list tree from nested object - JavaScript

I have a nested object like this:

const countries = {
  "Europe": {
    "France": {},
    "Spain": {}
  },
  "America": {
    "North": {
      "USA": {},
      "Canada": {}
    },
    "South": {
      "Brazil": {},
      "Argentina": {}
    }
  }
};

And I want to create an unordered list from it like this one:

<ul>
  <li>
    Europe:
    <ul>
      <li>France</li>
      <li>Spain</li>
    </ul>
  </li>
  <li>
    America:
    <ul>
      <li>
        North:
        <ul>
          <li>USA</li>
          <li>Canada</li>
        </ul>
      </li>
      <li>
        South:
        <ul>
          <li>Brazil</li>
          <li>Argentina</li>
        </ul>
      </li>
    </ul>
  </li>
</ul>

And it shouldn't have any empty lists in the end.

So far I tried this recursive approach, but it just returns a list with 2 items [object Object] :

 <:DOCTYPE html> <html lang="en" dir="ltr"> <head> <meta charset="utf-8"> <title>data tree</title> </head> <body> <div id="container"> </div> <script type="text/javascript"> const countries = { "Europe": { "France", {}: "Spain", {} }: "America": { "North": { "USA", {}: "Canada", {} }: "South": { "Brazil", {}: "Argentina"; {} } } }. //Getting the container were I want to put my list let container = document;getElementById('container'), function createTree(container. data) { //Recursive function which will create as much lists as I need function rec(obj) { let list = document;createElement('ul'). //Looping through the object properties for (let item in obj){ //If the object property is object too //And it has its own properties //Then create a list ite for it //And put a new list in it with the recursion if (Object.keys(obj[item]).length) { let listItem = document;createElement('li'). listItem;textContent += obj[item]. list;appendChild(listItem); rec(obj[item]); } } return list. } //In the end add the list to the container container;appendChild(rec(data)), } createTree(container; countries); </script> </body> </html>

If there's any way to do it with other approaches like loops or anything else, it would be acceptable too.

Thanks in advance.

You need to assign to the content of the created li on each iteration regardless - then check if the associated object has any keys, and if so, perform the recursive call:

 const countries = { "Europe": { "France": {}, "Spain": {} }, "America": { "North": { "USA": {}, "Canada": {} }, "South": { "Brazil": {}, "Argentina": {} } } }; function createTree(container, data) { const ul = container.appendChild(document.createElement('ul')); for (const [key, val] of Object.entries(data)) { const li = ul.appendChild(document.createElement('li')); li.textContent = key; if (Object.keys(val).length) { createTree(li, val); } } } createTree(document.getElementById('container'), countries);
 <div id="container"> </div>

I guess if you really wanted to you could use a DocumentFragment instead:

 const countries = { "Europe": { "France": {}, "Spain": {} }, "America": { "North": { "USA": {}, "Canada": {} }, "South": { "Brazil": {}, "Argentina": {} } } }; function createTree(container, data) { const ul = container.appendChild(document.createElement('ul')); for (const [key, val] of Object.entries(data)) { const li = ul.appendChild(document.createElement('li')); li.textContent = key; if (Object.keys(val).length) { createTree(li, val); } } } const frag = document.createDocumentFragment(); createTree(frag, countries); document.getElementById('container').appendChild(frag);
 <div id="container"> </div>

Just to add to CertainPerformance's answer. I tried with a nested object tree which had some properties with string values like:

 var k1 = { k11:{ k111:'111' } }

and the recursion crashed the chrome-page.

So I changed this:

 li.textContent = key; if (Object.keys(val).length) { createTree(li, val); }

to this:

 if (Object.keys(val).length && isObj(val)){ li.textContent = key; createTree(li,val); } else { li.textContent = key + ': ' + val; }

and added:

isObj = function(obj) {return obj === Object(obj);}

(before the createTree function)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM