2

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))

3
  • @ValiD tree will be any nested structure. so i'm doing that way Commented Feb 8, 2021 at 13:36
  • Is the data structure allowed to change? I would probably have an array of child objects as a property on the each list item object, which makes the recursive generation a lot simpler. Commented Feb 8, 2021 at 14:08
  • @DBS, why not but with minimum loops Commented Feb 8, 2021 at 14:09

2 Answers 2

2

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>

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

1 Comment

solution seems to be good, but i want to apply it on flat list based on id,parentId
1

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?

3 Comments

it is forming separate ul for each nested tree. atleast it should work with 2 to 3 levels of nesting
i have edited my tree list, still your updated code is not working
Can you share the dataset you are working with, to see where it fails?

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.