How to get html nested structure with ul, li for a tree data array

Viewed 434

Hi i want to get nested tree structure based on nesting

Something like this

<ul> 
   <li>Root 
      <ul>
        <li>First level item 1</li>
        <li>
          First level item 2
            <ul>
               <li>second level item1</li>
            </ul>
        </li>
     </ul>
</li>

Question: my function is not returning tree structure markup properly.

Note: i don't want to add 1 more loop

Here is what i have tried:

var getTreeStrucureTemplate = dataset => {
  var hashTable = Object.create(null), ul = '',li = '';
 dataset.forEach(function(aData){
     hashTable[aData.id] = {...aData, childNodes: []};
     ul = '<ul>';
  });
  var dataTree = [];
  dataset.forEach(aData => {
    
    if(aData.parentId) { hashTable[aData.parentId].childNodes.push(hashTable[aData.id]);  ul += '<li>'+aData.name+'</li>';}
    else { dataTree.push(hashTable[aData.id]);  ul += '</ul><ul>' }

   // console.log(ul);
  });
  //console.log(dataTree);
  var treeStructure = ul;
  return treeStructure;
};

var list = [
{
    "parentId": 0,
    "id": 1,
    "name": "Root"
},

{
    "parentId": 1,
    "id": 2,
    "name": "First Level item 1"
},

{
    "parentId": 1,
    "id": 3,
    "name": "First Level item 2"
},

{
    "parentId": 3,
    "id": 4,
    "name": "second Level item 1"
}
];

console.log(getTreeStrucureTemplate(list))

2 Answers

This is how I would go about this:

  • Use a nested data structure with each object containing it's children
  • Use a set of recursive functions that call each other to automatically deal with any number of layers

(It only runs as many times as needed, but whether your consider recursive functions as loops is up to you)

var getListItems = dataset => {
  // Create a string containing the items for this list
  return dataset.map(item => {
    // Build a nested UL string by calling getTreeStrucureTemplate on this objects children
    var nested = getTreeStrucureTemplate(item.children || [])
    // Build the current item and add any nested lists
    return `<li>${ item.name }</li>${ nested }`
  }).join('') // Join the items into a single string
}

var getTreeStrucureTemplate = dataset => {
  // Only wrap the list in UL if it has contents
  if (dataset.length) {
    return `<ul>${ getListItems(dataset) }</ul>`
  } else {
    return ''
  }
};

var list = [{
    "name": "A",
    "children": [{
      "name": "B",
      "children": [{
        "name": "C"
      },
      {
        "name": "D"
      }]
    }]
  },
  {
    "name": "E",
    "children": [{
      "name": "F"
    }]
  }
]

var test = getTreeStrucureTemplate(list)

document.getElementById('test').innerHTML = test
console.log(test)
<div id="test"></div>

I tried to work with the structure that you have given here in your question. I don't really understand where you don't want to use another loop, but here is my suggestion to resolve your problem.

var getTreeStrucureTemplate = dataset => {
  var hashTable = {}, ul = '',li = '';
    var dataTree = [];
    
    dataset.forEach(item => {
         if (item.parentId) {
            if (hashTable[item.parentId]) {
                hashTable[item.parentId].childNodes.push(item);
            } else {
                hashTable[item.parentId] = {id: item.patentId, childNodes: [item]};         
            }
         } else {
            hashTable[item.id] = {...item, childNodes: []};
         }
  });
    
    console.log('-=-=-=-=-=-=-=-=-=-=-=-=-=-');
    console.log(hashTable)
    console.log('-=-=-=-=-=-=-=-=-=-=-=-=-=-');
  

    Object.values(hashTable).forEach(node => {
        ul += '<ul>' + node.name;
        node.childNodes.forEach(subNode => {
            ul += '<li>' + subNode.name + '</li>';
        });
        ul += '</ul>';
    })
  
  return ul;
};

var list = [
    {
        "parentId": 0,
        "id": 1,
        "name": "First Level"
    },
    {
        "parentId": 1,
        "id": 2,
        "name": "First Level item 1"
    },
    {
        "parentId": 0,
        "id": 3,
        "name": "First Level 2"
    },
    {
        "parentId": 3,
        "id": 4,
        "name": "First Level 2 item 1"
    }
];


console.log(getTreeStrucureTemplate(list))

I am printing the array after it is reformatted to the desired way. I think you can improve this code in terms of performance if you see fit, but the way it is written here should be pretty clear about what we are trying to accomplish.

I hope it would help.

updated version to support as many nested levels as you would like:

var getTreeStrucureTemplate = dataset => {
  var hashTable = {}, ul = '',li = '';
    var dataTree = [];
    
    dataset.forEach(item => {
        if (item.parentId) {
            if (hashTable[item.parentId]) {
                hashTable[item.parentId].childNodes.push(item);
            } else {
                hashTable[item.parentId] = {id: item.patentId, childNodes: [item]};         
            }
        } else {
            hashTable[item.id] = {...item, childNodes: []};
        }
  });
    
    console.log('-=-=-=-=-=-=-=-=-=-=-=-=-=-');
    console.log(hashTable)
    console.log('-=-=-=-=-=-=-=-=-=-=-=-=-=-');
  

    Object.values(hashTable).forEach(node => {
        ul += createSubTree(node);
    })
  
  return ul;
};

var createSubTree = tree => {
    var str = '';
    str += '<ul>' + tree.name;
    tree.childNodes.forEach(subNode => {
        str += '<li>' + subNode.name + '</li>';
        if (subNode.childNodes && subNode.childNodes.length) {
            str += createSubTree(subNode.childNodes);
        }
    });
    str += '</ul>';

    return str;
}

var list = [
    {
        "parentId": 0,
        "id": 1,
        "name": "First Level"
    },
    {
        "parentId": 1,
        "id": 2,
        "name": "First Level item 1"
    },
    {
        "parentId": 0,
        "id": 3,
        "name": "First Level 2"
    },
    {
        "parentId": 3,
        "id": 4,
        "name": "First Level 2 item 1"
    }
];


console.log(getTreeStrucureTemplate(list))

is that what you are looking for?

Related