0

I have a problem with deep copy/clone on a object (TypeScript,Angular4,Ionic3) that also holds a list of other objects. Whenever I change the child objects in the copy, the original is also inflicted by the change and vice versa. My REST API gives me the following JSON back:

enter image description here

I have 2 types of objects that are relevant in this case, there are more but they do not need to be changed, therefore I do not include those:

import { Declaration } from './declaration.entity';

export class Period{
    constructor(
        public number: number,
        public status: string,
        public year: number,
        public month: number,
        public sum: number,
        public orderNumber: string,
        public userId: string,
        public submitDate: Date,
        public comment: string,
        public declarations: Declaration[]
    ){}
}

And

import { FileCustom } from './file.entity';
import { Period } from './period.entity';

export class Declaration{
    constructor(
        public id: number,
        public status: string,
        public name: string,
        public description: string,
        public amount: number,
        public date: Date,
        public period: Period,
        public userId: string,
        public files: FileCustom[],
        public comment: string   
    ){}
}

I want to change the field of a Declaration that is inside a Period. I have a object called periods (list of periods), which I want to clone. I need periods to be untouched. I looked at some other topics with possible solutions and tried them:

let cloned = this.periods.map(x => Object.assign({},x));

And

let cloned = this.periods.map(x => Object.assign([],x));

From this topic:

Deep copy an array in Angular 2 + TypeScript

When I use one of the above solutions and change for example the comment field of the period in the copy, the original file remains untouched. But when I change the comment field of the declaration inside the period, the original file is also changed, which is what I want to prevent. How can I deep copy/clone my list of periods without any children having any references to the original?

Thanks in advance.

icedwater
  • 4,701
  • 3
  • 35
  • 50
Niek Jonkman
  • 1,014
  • 2
  • 13
  • 31
  • 1
    `Object.assign` doesn't do a full deep copy by itself it just copies properties from one object to the other. If those properties contain other objects those references are going to be maintained. You probably wanted to look at [What is the most efficient way to deep clone an object in JavaScript?](https://stackoverflow.com/questions/122102/what-is-the-most-efficient-way-to-deep-clone-an-object-in-javascript) – Patrick Evans Jan 09 '18 at 15:43
  • 1
    Possible duplicate of [What is the most efficient way to deep clone an object in JavaScript?](https://stackoverflow.com/questions/122102/what-is-the-most-efficient-way-to-deep-clone-an-object-in-javascript) – toskv Jan 09 '18 at 15:52

2 Answers2

1

You can do it with lodash's cloneDeep function to avoid stringifying the objects back and forth.

For your Angular project, you can do it like this:

Install lodash with yarn add lodash or npm install lodash

Since we are going to use only the cloneDeep function, in order to reduce the bundle, we are going to only import the function into the component, not the whole lodash library:

import * as cloneDeep from 'lodash/cloneDeep';

The, we are going to use it like this to deep copy the objects:

copiedList = cloneDeep(originalList);

Now changing something into an object nested in the copy will not change the original object.

This solution will add 18 kb to your production Angular bundle.

BogdanC
  • 2,746
  • 2
  • 24
  • 22
0

If the object prototypes aren't an issue and objects don't contain functions you could JSON.stringify() and parse that back to new object

let cloned = this.periods.map(x => JSON.parse(JSON.stringify(x)));

Or stringify whole this.periods at one time

let cloned = JSON.parse(JSON.stringify(this.periods))
charlietfl
  • 170,828
  • 13
  • 121
  • 150
  • Thanks, I used your first solution and that worked for me. I'll mark this answer as the solution, however, I still don't fully comprehend. I will read through the topic marked as a duplicate (by Patrick & toskv) to understand this. – Niek Jonkman Jan 09 '18 at 16:05