0

I want to generate a Array Tree of Objects with different levels and positions. In my opinion the parentId can create the level as in "children". The position can sort the items.

  • Unlimited in levels and positions.

Can somebody help me out how I can achieve this?

I receive the following API data:

[ 
 { label: "Level one 1", id: 1, parentId: null, position: 0},
 { label: "Level two 1-1", id: 4, parentId: 1, position: 0},
 { label: "Level three 1-1-1", id: 9, parentId: 4, position: 1},
]

Here is an example how I want the data in the end:

const dataSource = ref([
  {
    id: 1,
    position: 0,
    parentId: null,
    label: 'Level one 1',
    children: [
      {
        id: 4,
        position: 0,
        parentId: 1,
        label: 'Level two 1-1',
        children: [
          {
            id: 9,
            parentId: 4,
            position: 0,
            label: 'Level three 1-1-1',
          },
          {
            id: 10,
            parentId: 4,
            position: 1,
            label: 'Level three 1-1-2',
          },
        ],
      },
    ],
  },
  {
    id: 2,
    position: 1,
    parentId: null,
    label: 'Level one 2',
    children: [
      {
        id: 5,
        position: 0,
        parentId: 2,
        label: 'Level two 2-1',
      },
      {
        id: 6,
        position: 1,
        parentId: 2,
        label: 'Level two 2-2',
      },
    ],
  },
  {
    id: 3,
    position: 2,
    parentId: null,
    label: 'Level one 3',
    children: [
      {
        id: 7,
        position: 0,
        parentId: 3,
        label: 'Level two 3-1',
      },
      {
        id: 8,
        position: 1,
        parentId: 3,
        label: 'Level two 3-2',
      },
    ],
  },
])

3 Answers 3

2

for this you can combine map method to redefine item in your array and filter to get only child of a parent object

var data = [ 
 { label: "Level one 1", id: 1, parentId: null, position: 0},
 { label: "Level two 1-1", id: 4, parentId: 1, position: 0},
 { label: "Level three 1-1-1", id: 9, parentId: 4, position: 1},
];

var result  = data.map(elem => {
  elem.children = data.filter(item => item.parentId === elem.id);
  return elem;
});

console.log(result);

Sign up to request clarification or add additional context in comments.

Comments

0

You could take a ingle loop approach with an object as reference for each node.

const
    getTree = (data, root) => {
        const t = {};
        data.forEach(o => ((t[o.parentId] ??= {}).children ??= []).push(Object.assign(t[o.id] ??= {}, o)));
        return t[root].children;
    },
    data = [{ label: "Level one 1", id: 1, parentId: null, position: 0 }, { label: "Level two 1-1", id: 4, parentId: 1, position: 0 }, { label: "Level three 1-1-1", id: 9, parentId: 4, position: 1 }],
    tree = getTree(data, null);

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

2 Comments

This is working. But it doesn't do anything with the position. Position 0, should be index 0. Position 1, should be index 1. How to sort that out?
what should be in pos 0 if no data is available?
0

This solution first create a copy of each object, and stores it in a Map instance. I manually add the key null with value { children: [] }, so we can handle/find the root object easily.

After creating the Map instance, I loop over each records. Fetch both the copy of the record itself and the parent. Then assign parent.children to an array if it's not present. Finally I assign the record as a child of parent based on its position.

function recordsToTree(records) {
  const lookup = new Map(records.map(({ ...record }) => [record.id, record]));
  lookup.set(null, { children: [] });

  for (const { id, parentId, position } of records) {
    const record = lookup.get(id);
    const parent = lookup.get(parentId);
    
    parent.children ||= [];
    parent.children[position] = record;
  }
  
  return lookup.get(null).children;
}

console.log(
  recordsToTree([
    { label: "Level three 1-1-2", id: 3, parentId:    4, position: 1 },
    { label: "Level one 1",       id: 1, parentId: null, position: 0 },
    { label: "Level three 1-1-1", id: 9, parentId:    4, position: 0 },
    { label: "Level two 1-1",     id: 4, parentId:    1, position: 0 },
  ])
);

If position does not reflect the index of a child element you could use parent.children.push(record) instead of parent.children[position] = record.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.