Home > Blockchain >  Create menu path from parent child relation
Create menu path from parent child relation

Time:05-04

Given this array of objects:

[
  {
    "id": 1942,
    "label": "1",
    "url": "",
    "homepage": false,
    "visible": true,
    "order": 1
  },
  {
    "id": 1943,
    "label": "a",
    "url": "",
    "parentId": 1942,
    "homepage": false,
    "visible": true,
    "order": 1
  },
  {
    "id": 1944,
    "label": "aa",
    "url": "",
    "parentId": 1942,
    "homepage": false,
    "visible": true,
    "order": 2
  },
  {
    "id": 1945,
    "label": "aaa",
    "url": "",
    "parentId": 1942,
    "homepage": false,
    "visible": true,
    "order": 3
  },
  {
    "id": 1946,
    "label": "a1",
    "url": "",
    "parentId": 1943,
    "homepage": false,
    "visible": true,
    "order": 1
  },
  {
    "id": 1947,
    "label": "a2",
    "url": "",
    "parentId": 1943,
    "homepage": false,
    "visible": true,
    "order": 2
  },
  {
    "id": 1948,
    "label": "2",
    "url": "",
    "homepage": false,
    "visible": true,
    "order": 2
  },
  {
    "id": 1949,
    "label": "b",
    "url": "",
    "parentId": 1948,
    "homepage": false,
    "visible": true,
    "order": 1
  },
  {
    "id": 1950,
    "label": "b1",
    "url": "",
    "parentId": 1949,
    "homepage": false,
    "visible": true,
    "order": 1
  },
  {
    "id": 1951,
    "label": "bb",
    "url": "",
    "parentId": 1948,
    "homepage": false,
    "visible": true,
    "order": 2
  },
  {
    "id": 1952,
    "label": "b2",
    "url": "",
    "parentId": 1949,
    "homepage": false,
    "visible": true,
    "order": 2
  }
]

I need to create a menu with links based on parent child relations.

The new array i need has to have the following struture of objects.

1

1 / a

1 / aa

1 / aaa

1 / a / a1

1 / a / a2

2

2 / b

2 / bb

2 / b / b1

2 / b / b2

I have tried with recursion without luck:

 convert(array) {
    const x = array
      .filter((m, i) => m.id === array[i].parentId)
      .map((menuItem) => ({
        parent: menuItem,
        children: convert(array),
      }));
      console.log(x)
  }

And i tried with loops, but this aproach only gets limited levels and i need infinite levels of deep.

convert() {
    let parents = array.filter((p) => !p.parentId);
    const children = array.filter((c) => c.parentId);
    let combined = [];
    for (var i = 0; i < parents.length; i  ) {
      for (var j = 0; j < children.length; j  ) {
        if (children[j].parentId === parents[i].id) {
          combined.push([parents[i], children[j]]);
        }
      }
    }

    console.log(combined);
  }

EDIT: I was able to do it with 3 levels deep. But with recursion for "infinite" levels deep, could not figured out.

convert() {
    let parents = this.config.menuItems.filter((p) => !p.parentId);
    const children = this.config.menuItems.filter((c) => c.parentId);
    let combined = [];
    for (var i = 0; i < parents.length; i  ) {
      for (var j = 0; j < children.length; j  ) {
        if (children[j].parentId === parents[i].id) {
          combined.push([parents[i], children[j]]);
        }
        for (var k = 0; k < children.length; k  ) {
          if (children[j].id === children[k].parentId && parents[i].id === children[j].parentId) {
            combined.push([parents[i], children[j], children[k]]);
          }
        }
      }
    }

    console.log(combined);
  }

CodePudding user response:

Here's a recursive method that I think probably works. If you didn't want to use the page_children_map you could replace page_children_map.get(page.id) with pages.filter(({ parentId }) => parentId === page.id).

const pages = [{"id":1942,"label":"1","url":"","homepage":false,"visible":true,"order":1},{"id":1943,"label":"a","url":"","parentId":1942,"homepage":false,"visible":true,"order":1},{"id":1944,"label":"aa","url":"","parentId":1942,"homepage":false,"visible":true,"order":2},{"id":1945,"label":"aaa","url":"","parentId":1942,"homepage":false,"visible":true,"order":3},{"id":1946,"label":"a1","url":"","parentId":1943,"homepage":false,"visible":true,"order":1},{"id":1947,"label":"a2","url":"","parentId":1943,"homepage":false,"visible":true,"order":2},{"id":1948,"label":"2","url":"","homepage":false,"visible":true,"order":2},{"id":1949,"label":"b","url":"","parentId":1948,"homepage":false,"visible":true,"order":1},{"id":1950,"label":"b1","url":"","parentId":1949,"homepage":false,"visible":true,"order":1},{"id":1951,"label":"bb","url":"","parentId":1948,"homepage":false,"visible":true,"order":2},{"id":1952,"label":"b2","url":"","parentId":1949,"homepage":false,"visible":true,"order":2}];

const page_children_map = pages.reduce(
  (acc, val) => {
    if(!val.parentId) return acc;
    
    let arr = acc.get(val.parentId);
    if(!arr) acc.set(val.parentId, arr = []);

    arr.push(val);

    return acc;
  },
  new Map()
);

const page_paths = (page, parent_list = []) => {
  let paths = [];
  
  const list = [...parent_list, page];
  const children = page_children_map.get(page.id);
  
  paths.push(list);
  if(children?.length)
    paths.push(...children.flatMap((child) => page_paths(child, list)));
  
  return paths;
};

const res = pages
  .filter(({ parentId }) => !parentId)
  .reduce((acc, val) => {
    acc.push(...page_paths(val));
    return acc;
  }, [])
  .map( (crumbs) => crumbs.map(({ label }) => label).join(' / ') );

console.log(res);

  • Related