How to change the response using of JSON using function?

Viewed 120

I am calling a function buildFileTree and saving it's response into data which is constant

const data = this.buildFileTree(dataObject, 0);

where dataObject is:

 const dataObject =  JSON.parse(TREE_DATA);

And TREE_DATA is:

const TREE_DATA = JSON.stringify([
{
    Standard: "Food",
    Category: [
      {
        Name: "Vegetable",
        Tables: [
          {
            Description:
              "The carrot is a simple root vegetable, usually conical or cylindrical in shape.",
            Name: "Carrots"
          },
          {
            Description:
              " tomatoes come in a wide variety of shapes: round, oblate, pear-shaped, torpedo-shaped,",
            Name: "Tomatoes"
          }
        ]
      },
      {
        Name: "Fruits",
        Tables: [
          {
            Description: "Oranges",
            Name: "Spherical shape is of orange"
          },
          {
            Description: "Grapes",
            Name:
              "Grapes are typically an ellipsoid shape resembling a prolate spheroid."
          }
        ]
      }
    ]
  }
]);

And buildFileTree Function is:

buildFileTree(obj: { [key: string]: any }, level: number): FileNode[] {
    return Object.keys(obj).reduce<FileNode[]>((accumulator, key) => {
      const value = obj[key];
      const node = new FileNode();
      node.filename = key;
      if (value != null) {
        if (typeof value === "object") {
          node.children = this.buildFileTree(value, level);
        } else {
          node.type = value;
        }
      }
      return accumulator.concat(node);
    }, []);
  }
}

Response from above function is:

Current Response

Expected Response : Format

It seems like I have to make some changes in buildFileTree function. Can I get some help with this?

Working Example for current response: https://stackblitz.com/edit/angular-qsb9c8-x4oaan?file=app%2Ftree-nested-overview-example.ts

2 Answers

There is no need to convert the array into a json and then create the necessary desired structure. Instead, work directly with the array treeData by iterating over each object and mapping the desired output as illustrated below:

var treeData = [
    {
      Standard: "Food",
      Category: [
        {
          Name: "Vegetable",
          Tables: [
            {
              Description:
                "The carrot .....  shape.",
              Name: "Carrots"
            },
            {
              Description:
                " tomatoes come .... torpedo-shaped,",
              Name: "Tomatoes"
            }
          ]
        },
        {
          Name: "Fruits",
          Tables: [
            {
              Name: "Oranges",
              Description: "Spherical shape is of orange"
            },
            {
              Name: "Grapes",
              Description:
                "Grapes ..... spheroid."
            }
          ]
        }
      ]
    }
  ];
  
let data = {};

for (const obj in treeData) {
  const inner = {};
  treeData[obj].Category.forEach(e => {
    inner[e.Name] = e.Tables.map(i => i.Name)
  });
  data[treeData[obj].Standard] = inner;
}

console.log(data);


From the comments, if you want to iterate over this in the template use the following snippet:

<div *ngFor="let e1 of data | keyvalue">
    {{ e1.key }}
    <ul *ngFor="let e2 of e1.value | keyvalue">
        <li>{{e2.key}}</li>
        <ul *ngFor="let e3 of e2.value | keyvalue">
            <li>{{e3.value}}</li>
        </ul>
    </ul>
</div>

The main problem with your function is that in the working example you're applying it to a Javascript Object, while your TREE_DATA is a Javascript Array.

With that said, if you use the Object.keys() method on an array, it will return the indexes of the elements in your array. E.g. Object.keys([10,20,30]); // returns ['0','1','2']

Your buildFileTree should be modified as follows

// Create a new JS object, where each key is a 'Standard' entry, and each value
// is another object with 'Category.Name' as key and an array with all the entries' Names as value 

const result = dataObject.reduce((acc1, e1) => {
  acc1[e1.Standard] = e1.Category.reduce((acc2, e2) => {
    acc2[e2.Name] = e2.Tables.map(e => e.Name);
    return acc2;
  }, {})
  return acc1;
}, {});

Hope it helped! If you're not familiar with the reduce and map methods you should definitely check into them!

Related