Flat array of objects to tree in JavaScript

Converting a flat array of objects into a tree structure is a common requirement in web development. This involves organizing objects with parent-child relationships into a hierarchical format.

The Data Structure

We start with a flat array where each object has an id, name, and parentId. Objects with parentId: null are root nodes, while others are children.

<!DOCTYPE html>
<html>
<head>
    <style>
        .parent, .child {
            cursor: pointer;
        }
        .parent {
            margin: 10px 0;
            font-size: 1.3rem;
        }
        .parent::before {
            content: "\25BA";
            margin-right: 10px;
        }
        .childContainer {
            margin-left: 20px;
            display: none;
        }
        .childContainer.visible {
            display: block;
        }
        .child {
            font-size: 1rem;
        }
        .child::before {
            content: "\25BA";
        }
    </style>
</head>
<body>
    <div id="tree"></div>
    
    <script>
        const arr = [
            { id: '1', name: 'name 1', parentId: null },
            { id: '2', name: 'name 2', parentId: null },
            { id: '2_1', name: 'name 2_1', parentId: '2' },
            { id: '2_2', name: 'name 2_2', parentId: '2' },
            { id: '3', name: 'name 3', parentId: null },
            { id: '1_1', name: 'name 1_1', parentId: '1' },
            { id: '1_2', name: 'name 1_2', parentId: '1' },
            { id: '2_1_1', name: 'name 2_1_1', parentId: '2_1' },
            { id: '2_1_2', name: 'name 2_1_2', parentId: '2_1' }
        ];

        const tree = document.getElementById("tree");
        
        // Process each object in the array
        arr.forEach(item => {
            const div = document.createElement("div");
            
            if (item.parentId === null) {
                // Create root level elements
                div.classList.add("parent");
                div.setAttribute("id", `id${item.id}`);
                div.innerText = item.name;
                tree.appendChild(div);
            } else {
                // Create child elements
                const parent = document.getElementById(`id${item.parentId}`);
                
                if (!parent.classList.contains("parent")) {
                    parent.classList.add("parent");
                }
                
                let childContainer = parent.querySelector(".childContainer");
                
                if (!childContainer) {
                    childContainer = document.createElement("div");
                    childContainer.classList.add("childContainer");
                    parent.appendChild(childContainer);
                }
                
                div.classList.add("child");
                div.setAttribute("id", `id${item.id}`);
                div.innerText = item.name;
                childContainer.appendChild(div);
            }
        });
        
        // Add click handlers for expanding/collapsing
        const parents = Array.from(document.getElementsByClassName("parent"))
            .filter(p => p.querySelector(".childContainer"));
            
        parents.forEach(parent => {
            parent.addEventListener("click", function(e) {
                e.preventDefault();
                const container = this.querySelector(".childContainer");
                if (container) {
                    container.classList.toggle("visible");
                }
                e.stopPropagation();
            });
        });
    </script>
</body>
</html>

How It Works

The algorithm processes the flat array and builds a DOM tree structure:

  1. Root Elements: Objects with parentId: null are added directly to the main container
  2. Child Elements: Objects with a parentId are appended to their parent's child container
  3. Dynamic Containers: Child containers are created only when needed
  4. Interactive Behavior: Click handlers allow expanding/collapsing of parent nodes

Alternative Approach: Pure Data Transformation

For cases where you need the tree as a data structure rather than DOM elements:

const arr = [
    { id: '1', name: 'name 1', parentId: null },
    { id: '2', name: 'name 2', parentId: null },
    { id: '2_1', name: 'name 2_1', parentId: '2' },
    { id: '1_1', name: 'name 1_1', parentId: '1' }
];

function buildTree(flatArray) {
    const map = {};
    const roots = [];
    
    // Create a map of all items
    flatArray.forEach(item => {
        map[item.id] = { ...item, children: [] };
    });
    
    // Build the tree structure
    flatArray.forEach(item => {
        if (item.parentId === null) {
            roots.push(map[item.id]);
        } else {
            const parent = map[item.parentId];
            if (parent) {
                parent.children.push(map[item.id]);
            }
        }
    });
    
    return roots;
}

const tree = buildTree(arr);
console.log(JSON.stringify(tree, null, 2));
[
  {
    "id": "1",
    "name": "name 1",
    "parentId": null,
    "children": [
      {
        "id": "1_1",
        "name": "name 1_1",
        "parentId": "1",
        "children": []
      }
    ]
  },
  {
    "id": "2",
    "name": "name 2",
    "parentId": null,
    "children": [
      {
        "id": "2_1",
        "name": "name 2_1",
        "parentId": "2",
        "children": []
      }
    ]
  }
]

Key Points

  • The DOM approach directly creates interactive HTML elements
  • The data transformation approach creates a reusable tree structure
  • Both methods handle unlimited nesting levels
  • CSS provides visual hierarchy with indentation and arrows

Conclusion

Converting flat arrays to trees is essential for displaying hierarchical data like menus, categories, or organizational charts. Choose the DOM approach for immediate visualization or the data transformation method for further processing.

Updated on: 2026-03-15T23:19:00+05:30

814 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements