1

Given a nested array of objects, I am trying to write in a nested unordered list.

The arrays themselves are organized so that every new children property, starts a new array of objects. The function needs to be able to support n level depth.

My current solution can recursively write all the properties I need now, but appends the < li> tags at the wrong < ul>.

I think this is because of :

  var lowUL = targetUL.querySelector('ul');

which I use in my recursive base case to append < li> too. It only selects the first < ul> tag it finds, and not the dynamically created < ul> tag from that iteration in the for loop.

// DATA
const org1_depts = [
  {
    name: 'accounting',
    children: [
      { name: 'accounting payable', children: [] },
      { name: 'accounting receivable', children: [] },
    ],
  },
  {
    name: 'finance',
    children: [],
  },
]

const org2_depts = [
  {
    name: 'accounting',
    children: [
      { name: 'accounting payable', children: [] },
      {
        name: 'accounting receivable',
        children: [{ name: 'cash', children: [] }, { name: 'check', children: [] }],
      },
    ],
  },
  {
    name: 'finance',
    children: [{ name: 'investment', children: [] }],
  },
]

// FUNCTION

function listOrg(orgData,targetUL) {
  var i;
  for (i = 0; i < orgData.length; i++) {
    if (orgData[i].hasOwnProperty('name')) {
      // Take out the text from the .name property
      var nameText = document.createTextNode(orgData[i].name);
      // Define a new <li> tag
      var newLI = document.createElement('li');
      // Append text to new <li> tage - newLI
      newLI.appendChild(nameText);
      // Append element to <ul> tag
      targetUL.appendChild(newLI);
    }

    if (orgData[i].hasOwnProperty('children')) {
      // Define new <ul> tag
      var newUL = document.createElement('ul');
      // Append new <ul> tag
      var lowUl = targetUL.appendChild(newUL);
      // Select new lower level <ul> tag
      var lowUL = targetUL.querySelector('ul');
      // Recurse
      listOrg(orgData[i].children,lowUL);
    }
  }
}

// CALL FUNCTION
listOrg(org1_depts,document.getElementById("org1"));
listOrg(org2_depts,document.getElementById("org2"));
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
<ul id='org1'>
  Organization 1
</ul>

<ul id='org2'>
  Organization 2
</ul>

</body>
</html>

Above the child name properties from "accounting receivable" are being placed inside of "accounting payable", which is wrong.

1 Answer 1

3

When you recursively call the listOrg function, you should send the newUL variable as a parameter instead of lowUL. listOrg(orgData[i].children,newUL) this will target the newly created ul, you have no need to use querySelector

// DATA
const org1_depts = [
  {
    name: 'accounting',
    children: [
      { name: 'accounting payable', children: [] },
      { name: 'accounting receivable', children: [] },
    ],
  },
  {
    name: 'finance',
    children: [],
  },
]

const org2_depts = [
  {
    name: 'accounting',
    children: [
      { name: 'accounting payable', children: [] },
      {
        name: 'accounting receivable',
        children: [{ name: 'cash', children: [] }, { name: 'check', children: [] }],
      },
    ],
  },
  {
    name: 'finance',
    children: [{ name: 'investment', children: [] }],
  },
]

// FUNCTION

function listOrg(orgData,targetUL) {
  var i;
  for (i = 0; i < orgData.length; i++) {
    if (orgData[i].hasOwnProperty('name')) {
      // Take out the text from the .name property
      var nameText = document.createTextNode(orgData[i].name);
      // Define a new <li> tag
      var newLI = document.createElement('li');
      // Append text to new <li> tage - newLI
      newLI.appendChild(nameText);
      // Append element to <ul> tag
      targetUL.appendChild(newLI);
    }

    if (orgData[i].hasOwnProperty('children')) {
      // Define new <ul> tag
      var newUL = document.createElement('ul');
      // Append new <ul> tag
      var lowUl = targetUL.appendChild(newUL);
      // Select new lower level <ul> tag
      var lowUL = targetUL.querySelector('ul');
      // Recurse
      listOrg(orgData[i].children,newUL );
    }
  }
}

// CALL FUNCTION
listOrg(org1_depts,document.getElementById("org1"));
listOrg(org2_depts,document.getElementById("org2"));
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
<ul id='org1'>
  Organization 1
</ul>

<ul id='org2'>
  Organization 2
</ul>

</body>
</html>

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

1 Comment

Why does that work out? Wouldn't it just append the < li > tag to the root < ul > tag and not its child? Also, thank you for the solution

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.