Dev Aggarwal
Dev Aggarwal

Reputation: 783

Javascript - Convert Nested Object to Array of items

I have a object which looks like this:

[
  {
    "id": 1,
    "name": "Electronics",
    "path": "Electronics",
    "children": [
      {
        "id": 2,
        "name": "Laptops & PC",
        "path": "Electronics > Laptops & PC",
        "children": []
      },
      {
        "id": 7,
        "name": "Phones & Accessories",
        "path": "Electronics > Phones & Accessories",
        "children": [
          {
            "id": 8,
            "name": "Smartphones",
            "path": "Electronics > Phones & Accessories > Smartphones",
            "children": [
              {
                "id": 9,
                "name": "Android",
                "path": "Electronics > Phones & Accessories > Smartphones > Android",
                "children": []
              },
              {
                "id": 10,
                "name": "iOS",
                "path": "Electronics > Phones & Accessories > Smartphones > iOS",
                "children": []
              }
            ]
          }
        ]
      }
    ]
  },
  {
    "id": 11,
    "name": "Software",
    "path": "Software",
    "children": []
  }
]

And I wanted to convert it to something like this:

[
  {header: 'Electronics'},
  {name: 'Laptops & PC', group: 'Electronics', id: 2},
  {name: 'Phones & Accessories', group: 'Electronics', id: 7},
  {name: 'Smartphones', group: 'Phones & Accessories', id: 8},
  {name: 'Android', group: 'Smartphones', id: 9},
  {name: 'iOS', group: 'Smartphones', id: 10},
  {divider: true},
  {name: 'Software', group: 'Software', id: 11}
]

Basically,

While I was able to find lots of Hierarchical to JSON solutions on stackoverflow, I was not able to reverse engineer those solutions.

Can somebody please help me?

Upvotes: 1

Views: 960

Answers (2)

Nina Scholz
Nina Scholz

Reputation: 386550

You could take an iterative and recursive approach by checking header keeping the corresponding divider and iterate children.

Then you need to add the standard object for any item.

The recursive callback uses a closure over the group. if not set, the group is a root item.

function getParts(array) {
    var result = [];
    array.forEach(function iter(group) {
        return function ({ id, name, children }, i, { length }) {
            if (!group && children.length) {
                result.push({ header: name });
            }
            if (group || !children.length) {
                result.push({ name, group: group || name, id });
            }
            children.forEach(iter(name));
            if (!group && i + 1 !== length) {
                result.push({ divider: true });
            }
        };
    }(''));
    return result;
}

var data = [{ id: 1, name: "Electronics", path: "Electronics", children: [{ id: 2, name: "Laptops & PC", path: "Electronics > Laptops & PC", children: [] }, { id: 7, name: "Phones & Accessories", path: "Electronics > Phones & Accessories", children: [{ id: 8, name: "Smartphones", path: "Electronics > Phones & Accessories > Smartphones", children: [{ id: 9, name: "Android", path: "Electronics > Phones & Accessories > Smartphones > Android", children: [] }, { id: 10, name: "iOS", path: "Electronics > Phones & Accessories > Smartphones > iOS", children: [] }] }] }] }, { id: 11, name: "Software", path: "Software", children: [] }, { id: 11, name: "Software", path: "Software", children: [] }, { id: 11, name: "Software", path: "Software", children: [] }],
    result = getParts(data);

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 2

ggorlen
ggorlen

Reputation: 56875

Here's a recursive approach using array.reduce and the spread operator (...) to flatten lists as you move through the data, and a separate helper function to take care of non-headers:

const flatten = data => 
  data.reduce((a, e, i) => {
    if (e.children.length) {
      a.push({header: e.name});
      a.push(...flattenR(e.children, e.name));
    }
    else {
      a.push({name: e.name, group: e.name, id: e.id});
    }
    
    if (i < data.length - 1) {
      a.push({divider: true});
    }
    
    return a;
  }, [])
;

const flattenR = (data, grp) => 
  data.reduce((a, e) => {
    a.push({name: e.name, group: grp, id: e.id});
    a.push(...flattenR(e.children, e.name));
    return a;
  }, [])
;

const data = [
  {
    "id": 1,
    "name": "Electronics",
    "path": "Electronics",
    "children": [
      {
        "id": 2,
        "name": "Laptops & PC",
        "path": "Electronics > Laptops & PC",
        "children": []
      },
      {
        "id": 7,
        "name": "Phones & Accessories",
        "path": "Electronics > Phones & Accessories",
        "children": [
          {
            "id": 8,
            "name": "Smartphones",
            "path": "Electronics > Phones & Accessories > Smartphones",
            "children": [
              {
                "id": 9,
                "name": "Android",
                "path": "Electronics > Phones & Accessories > Smartphones > Android",
                "children": []
              },
              {
                "id": 10,
                "name": "iOS",
                "path": "Electronics > Phones & Accessories > Smartphones > iOS",
                "children": []
              }
            ]
          }
        ]
      }
    ]
  },
  {
    "id": 11,
    "name": "Software",
    "path": "Software",
    "children": []
  }
];

console.log(flatten(data));

Upvotes: 1

Related Questions