0

I have an array of objects that contains all my routes. I need to access all object's nested children properties & their properties and combining the together.

My array of object looks similar to this:

const routes = [
  {
    path: '/system-settings1',
    name: 'global-settings1',
    component: 'tabs1',
    children: [
      {
        path: 'level2-accounting1',
        name: 'local-settings1',
        components: 'modals1',
        children: [
          {
            path: 'level3-accounting1',
            name: 'local-settings1',
            components: 'modals1'
          }
          // more children deeply nested(or not)
        ]
      },
      {
        path: 'level2-accounting1',
        name: 'local-settings1',
        components: 'modals1',
        children: [
          {
            path: 'level3-accounting1',
            name: 'local-settings1',
            components: 'modals1'
          }
          // more children deeply nested(or not)
        ]
      }
    ],
  },
  {
    path: '/system-settings2',
    name: 'global-settings2',
    component: 'tabs2',
    children: [
      {
        path: 'level2-accounting2',
        name: 'local-settings2',
        components: 'modals2',
        children: [
          {
            path: 'level3-accounting2',
            name: 'local-settings2',
            components: 'modals2'
          }
          // more children deeply nested(or not)
        ]
      },
      {
        path: 'level3-accounting2',
        name: 'local-settings2',
        components: 'modals2',
        children: [
          {
            path: 'level4-accounting2',
            name: 'local-settings2',
            components: 'modals2'
          }
          // more children deeply nested(or not)
        ],
      }
    ],
  },
  // more objects with similar key/value pairs
];

I need to make the array of objects into single level array flat like so:

[
  {
    path: '/system-settings1',
    name: 'global-settings1',
    component: 'tabs1',
  },
  {
    path: 'level2-accounting2',
    name: 'local-settings2',
    components: 'modals2',
  },
  {
    path: 'level3-accounting1',
    name: 'local-settings1',
    components: 'modals1'
  },
  {
    path: 'level2-accounting1',
    name: 'local-settings1',
    components: 'modals1',
  }
  // so on if there is more objects etc
]

I have tried to .map() & .filter() combine with a while loop, but to be honest I'm lacking the skills to accomplish by my own & it's not worth to include my attempts. If anybody could assist me with this & explain it would be extremely appreciated.

Andrew Ault
  • 569
  • 3
  • 12
Manuel Abascal
  • 5,616
  • 5
  • 35
  • 68
  • 1
    in javascript (and most other languages), object keys must be unique, so you can't have more than one "path", "name", or "components" property on a single object. what are you trying to use the flat object for? EDIT - I think I understand the question now, I think the desired result is just confusing. – Andrew Ault Dec 10 '19 at 20:36
  • Sorry, I know it is confusing. I need to make a new array of objects with properties path, name, component of the parents and its children(and its children and so) into a one flatten array of object that I'll visualise on a table later on. – Manuel Abascal Dec 10 '19 at 20:41
  • you want one entry in the array for each route, regardless of whether it's a child or not, correct? – Andrew Ault Dec 10 '19 at 20:43
  • Yes, that's correct. It's basically grab all properties of children and its children and bring back to the first level. – Manuel Abascal Dec 10 '19 at 20:44

2 Answers2

1

I tried to edit your code examples so that they made sense and ran without errors. This is a recursive function that gets called on the root routes array, as well as any nested children arrays:

const flatten = routes => {
  const flattened = [];

  for (let i = 0; i < routes.length; i++) {
    const route = routes[i];

    //for each route, grab only the information about the route itself (no children)
    const { path, name, components } = route;
    const flatRoute = { path, name, components };

    //add the new route object to our return array
    flattened.push(flatRoute);

    //if the route had children, recursively call flatten on them
    //and add each child to our return array
    if (route.children) {
      const flatChildren = flatten(route.children);
      flattened.push(...flatChildren);
    }
  }

  return flattened;
};
Andrew Ault
  • 569
  • 3
  • 12
  • First of all, thanks for your help. I tried https://jsfiddle.net/ga8r31dh/ and I dont get it to work – Manuel Abascal Dec 10 '19 at 21:11
  • I think the code in your original post is invalid, because objects in the `routes` array have multiple children properties. see [this fiddle](https://jsfiddle.net/hr6q8afc/2/) for an example with the `routes` object cleaned up – Andrew Ault Dec 10 '19 at 21:22
1

Here's a pretty straightforward ES6 function. It is perhaps not the most performant version available, but it's simple.

const flattenAll = (xs) => xs .reduce (
  (all, {children, ...rest}) => [...all, {...rest}, ...flattenAll(children || [])],
  []
)

const routes = [{path: "/system-settings1", name: "global-settings1", component: "tabs1", children: [{path: "level2-accounting1", name: "local-settings1", components: "modals1", children: [{path: "level3-accounting1", name: "local-settings1", components: "modals1"}]}, {path: "level2-accounting1", name: "local-settings1", components: "modals1", children: [{path: "level3-accounting1", name: "local-settings1", components: "modals1"}]}]}, {path: "/system-settings2", name: "global-settings2", component: "tabs2", children: [{path: "level2-accounting2", name: "local-settings2", components: "modals2", children: [{path: "level3-accounting2", name: "local-settings2", components: "modals2"}]}, {path: "level3-accounting2", name: "local-settings2", components: "modals2", children: [{path: "level4-accounting2", name: "local-settings2", components: "modals2"}]}]}];

console .log (flattenAll (routes))

Note that this uses a depth-first ordering; I'm guessing that a breadth-first one would be significantly uglier code, but I haven't tried it.

Scott Sauyet
  • 49,207
  • 4
  • 49
  • 103