1

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,

  • If a root element has children, it should be converted as header.
  • All the elements should have its parent name as group
  • When finished with one root element, It needs to insert {divider: true} before proceeding to the next. (If it's the last root element, do not insert {divider: true}

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?

t.niese
  • 39,256
  • 9
  • 74
  • 101
Dev Aggarwal
  • 763
  • 1
  • 6
  • 19

2 Answers2

2

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; }
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
  • Accepted as Answer since faster than other answers and simpler to understand. – Dev Aggarwal Aug 26 '18 at 17:35
  • Hey, your code does not add divider if there are multiple root with no children. Can you please fix it? Here's the sample: https://jsfiddle.net/x8ghbnzr/ – Dev Aggarwal Aug 26 '18 at 18:40
  • @NinaScolz It works! thanks! Can you please explain the edit tho? – Dev Aggarwal Aug 26 '18 at 18:56
  • 1
    i removed the divider check and add a check for group (which is empty for root items) and if the item is not the last item with index and length. – Nina Scholz Aug 26 '18 at 19:03
  • Could you see this link guys..https://stackoverflow.com/questions/52039222/how-to-implement-hierarchical-multilevel-datatable-in-javascript?noredirect=1#comment91031196_52039222 – Varun Sharma Aug 28 '18 at 06:19
1

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));
ggorlen
  • 44,755
  • 7
  • 76
  • 106