Search code examples
angulartypescriptprimeng-tree

How can I clone a tree structure of an array of objects to another one, changing attributes to the cloned?


How can I clone a tree structure of an array of objects to another one, having different or less attibutes on the cloned one in TypeScript? For example on this:

[
   {
      "name":"root_1",
      "extradata":"whatever",
      "anArray":[
         { "id":1, "value":"test" },
         { "id":1, "value":"test" }
      ],
      "anObject":{ "id":1, "value":"test" },
      "children":[
         {
            "name":"child_1",
            "extradata":"whatever",
            "anArray":[],
            "anObject":{},
            "children":[
               {
                  "name":"root_1",
                  "extradata":"whatever",
                  "anArray":[],
                  "anObject":{},
                  "children":[]
               },
               {
                  "name":"root_1",
                  "extradata":"whatever",
                  "anArray":[],
                  "anObject":{},
                  "children":[]
               }
            ]
         }
      ]
   },
   {
      "name":"root_2",
      "extradata":"whatever",
      "anArray":[],
      "anObject":{},
      "children":[]
   }
]

I need a clone of it but instead of "name" the atribute "label", instad of "extradata" = "key" and without the "anArray" and "anObject". Like this:

[
   {
      "label":"root_1",
      "key":"whatever",
      "children":[
         {
            "label":"child_1",
            "key":"whatever",
            "children":[
               {
                  "label":"root_1",
                  "key":"whatever",
                  "children":[]
               },
               {
                  "label":"root_1",
                  "key":"whatever",
                  "children":[]
               }
            ]
         }
      ]
   },
   {
      "label":"root_2",
      "key":"whatever",
      "children":[]
   }
]

I need to clone it, to use it the data format for the primeng tree component.

I am trying with something like

this.myTree = tree.map((m, index) => Object.assign({}, {
                                label: m.name,
                                key: m.extradata,
                                children: m.children
                            }));

but the children are not following the same shape.


Solution

  • I would do this by first defining interfaces for the input and output types in question:

    interface InputTree {
      name: string,
      extradata: string,
      anArray: any[],
      anObject: object,
      children: InputTree[]
    }
    
    interface OutputTree {
      label: string,
      key: string,
      children: OutputTree[];
    }
    

    It looks like your input is an InputTree[] by that definition, and you want to produce an OutputTree[]. Trees are recursive, so you should write a treeMap() function that operates on an InputTree[] and then calls itself recursively on the children of each InputTree in the array. Like this:

    const treeMap = (inputTree: InputTree[]): OutputTree[] => inputTree.map(t => ({
      label: t.name,
      key: t.extradata,
      children: treeMap(t.children)
    }));
    
    const actual = treeMap(tree);
    

    You can verify that this produces the output you expect:

    console.log(JSON.stringify(expected)===JSON.stringify(actual)); // true
    

    Playground link to code