Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular2 - Cloning a variable to not modify source

I have a component which is displaying some data on a page from a subscription.

I am trying to clone that variable and make changes to it without impacting the original data being used to render the view of the page.

import { UtilsService } from '../shared';
import { Component, Input, OnInit } from '@angular/core';

@Component({
    selector: 'app-review',
    templateUrl: './review.component.html',
    styleUrls: ['./review.component.css']
})
export class ReviewComponent implements OnInit {

    @Input() payload: any = null;

    // Object of strings that are used for the details
    langStr: any = {
        noDepartment: 'No Department Change',
        noSegment: 'No Segment Change',
        noMarket: 'No Budget Market Change',
        noIncentive: 'No Incentive Plan Change',
        noRole: 'No Role Change',
        noProductionDate: 'No Production Date Change',
        noLanguage: 'No Language Change',
        noShift: 'No Shift Change',
        noSupervisor: 'No Supervisor Change'
    };

    // Used to scan through the final payload and assign default values if missing
    optionalFields = ['budgetMarket',
        'hierarchy',
        'incentivePlan',
        'primaryLanguage',
        'secondaryLanguage',
        'role',
        'segment',
        'shiftID',
        'supervisor'];

    modifiedData: any;

    constructor(
        private utils: UtilsService
    ) {
    }

    ngOnInit() { }

    submitChanges() {

        this.modifiedData = this.payload;

        // Loop over all of the keys in our formData object
        for (const key in this.modifiedData.formData) {

            // Find shift by property if the key exists within our defined array
            if (this.modifiedData.formData.hasOwnProperty(key) && this.utils.isInArray(this.optionalFields, key)) {

                // If our object data doesnt have a value, set it to -1
                if (!this.modifiedData.formData[key].length) {
                    this.modifiedData.formData[key] = '-1';
                }

            }

        }

        // Send to database 
        console.log(this.modifiedData)
    }

}

In this situation above, I am trying to set my subscribed data of this.payload to a new variable called modifiedData. I am then modifying some of the data in that assignment.

However, as soon as I call the function submitChanges(), my HTML view gets updates with the changes made to modifiedData, even though its not subscribed to that.

I assume it is something to do with this.modifiedData = this.payload; somehow updating the original data (payload).

Is there a way to do this where payload wouldn't be touched. I am essentially just cloning that and making a few changes before submitting it to my database call.

like image 657
SBB Avatar asked Jul 31 '17 17:07

SBB


2 Answers

Use something like this:

    // Clone the object to retain a copy
    this.originalProduct = Object.assign({}, value);

Or in your case:

    this.modifiedData = Object.assign({}, this.payload);

This copies the values of all properties from this.payload into a new object.

The documentation for this is here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign AND includes a discussion of the "deep cloning" issues.

Otherwise, this code:

 this.modifiedData = this.payload;

is assigning a reference. So any change to the original changes the "copy" as well.

like image 32
DeborahK Avatar answered Oct 05 '22 04:10

DeborahK


You're not cloning the object. You are just assigning the reference to that object to another variable. They both point at the exact same object.

If you want to actually clone your object you have basically two options:

First, easy, a little bit hacky and to be used carefully since not everything will be covered:

this.modifiedData = JSON.parse(JSON.stringify(this.payload));

will give you a new object basically cloned.

If you want to have a more robust cloning, you have to do it manually by traversing through your object and creating a new one from scratch (or use a library like lodash, which has methods for this).


Update just for completion: The other answers suggested this.modifiedData Object.assign({}, this.payload) and this.modifiedData = {...this.payload}; which is fine for simple, not nested objects because both do a shallow copy not a deep copy of your object.

Since JSON.parse(JSON.stringify(obj) will ignore everything else than Objects, Arrays, Numbers and Strings and Booleans, the probably best option to take is still a manual clone (or using a library which does it like lodash).

like image 61
malifa Avatar answered Oct 05 '22 03:10

malifa