Search code examples
javascripttypescriptmultidimensional-arraynested-lists

get data from unlimited nested array of objects


I got this data structure:-

interface DataType {
  level: number;
  type: string | number | arrayString | arrayNumber | arrayObj | obj;
  key: string;
  value: any;
  children: number[] // will store index of children
}

const data = [
  { level: 1, type: 'obj', key: 'obj1', value: {}, children: [1, 2] },
  { level: 2, type: 'string', key: 'obj1 child', value: 'child string', children: [] },
  { level: 2, type: 'obj', key: 'obj1 child obj', value: {}, children: [3] },
  { level: 3, type: 'obj', key: 'obj1-1', value: {}, children: [4] },
  { level: 4, type: 'obj', key: 'obj1-1-1', value: {}, children: [5] },
  { level: 5, type: 'string', key: 'obj1-1-1-1', value: 'last nest', children: [] },
]

Currently I'm trying to delete selected row & it's children. But in the same time also need to delete children's children's child... of selected row.

A. I only successfully able to delete selected row & it's direct children with the code below.

// let say current we inside .map of above data array of objects
// thus, we gonna have 'item' & 'index`

<button
  onClick={(): void => {
    let index2Delete: number[] = []

    data.forEach((item2, index2) => {
      if(index2 === index) {
        // include curr data index to be deleted later
        index2Delete.push(index2)

        // include children indexes to be deleted if have any
        if(item2.children.length > 0) {
          index2Delete = [...index2Delete, ...item2.children]
        }
      }
    })

    // filter those that need to be deleted
    const filtered = data.filter((item2, index2) => !index2Delete.includes(index2))

    // update new data list
    handleUpdateNewDataList(filtered)
  }}
>
  Delete
</button

B. But unsuccessful when trying to do recursive way. Got exceed limit something

// let say current we inside .map of above data array of objects
// thus, we gonna have 'item' & 'index`

<button
  onClick={(): void => {
    let index2Delete: number[] = []

    const repeatThis = (mainIndex: number) => {
      data.forEach((item2, index2) => {
        if(index2 === mainIndex) {
          // include curr data index to be deleted later
          // check first if already include index, since we're repeating this func
          if(!index2Delete.includes(index2))
            index2Delete.push(index2)

          // include children indexes to be deleted if have any
          if(item2.children.length > 0) {
            index2Delete = [...index2Delete, ...item2.children]

            // check if children got their own children
            item2.children.forEach((item3, index3) => {
              const childInfo = data.find((item4, index4) => index4 === item3)

              if(childInfo?.children.length > 0) 
                repeatThis(index3)
            })
          }
        }
      })
    }
    // run for main index
    repeatThis(index)

    // filter those that need to be deleted
    const filtered = data.filter((item2, index2) => !index2Delete.includes(index2))

    // update new data list
    handleUpdateNewDataList(filtered)
  }}
>
  Delete
</button

How can I adjust my code to make this work?


Solution

  • Here is my solution. First I created a function which calls out the levels I want to delete. For children, I called a recursive approach in which I also check that nested children won't repeat again and again to get infinite loop.

    let data = [
        { level: 1, type: 'obj', key: 'obj1', value: {}, children: [1, 2] },
        { level: 2, type: 'string', key: 'obj1 child', value: 'child string', children: [] },
        { level: 2, type: 'obj', key: 'obj1 child obj', value: {}, children: [3] },
        { level: 3, type: 'obj', key: 'obj1-1', value: {}, children: [4] },
        { level: 4, type: 'obj', key: 'obj1-1-1', value: {}, children: [5] },
        { level: 5, type: 'string', key: 'obj1-1-1-1', value: 'last nest', children: [] },
    ];  
    const levelToDelete = [];
    
    const deleteChildrenData = (data, children, curr) => {
     //   console.log('CHILDREN', children);
       children.forEach(c => {
          levelToDelete.push(c);
          const childIndexes = [];
          data.forEach((d, indx) => {
              if (d.level === c && curr.level !== c) {
                 childIndexes.push(indx);
              }
          });
          if (childIndexes.length) {            
               childIndexes.forEach(innerC => {
                console.log('DATA INNER C,', data[innerC]);
                const nestedChildren =  data[innerC].children.filter(c => c !== curr.level);
               if (nestedChildren.length > 0) {
                deleteChildrenData(data, nestedChildren, data[innerC]);
              }
            });
        }
       });
    }
    
    const deleteData = (data, index) => {
        data.forEach((curr, innerIndex) => {
            if (innerIndex === index) {
                levelToDelete.push(curr.level);
                if (curr.children.length && curr.type === 'arrObj' || curr.type === 'obj') {
                    const filteredChildren = curr.children.filter(c => c !== curr.level);
                    deleteChildrenData(data, filteredChildren, curr);
                }
            }
        } )
    }
    
    deleteData(data, 0, []);    
      // filter those that need to be deleted
      console.log(levelToDelete);
     const filtered = data.filter((item2, index2) => !levelToDelete.includes(item2.level))
    
    console.log(filtered);