[javascript] Why and when to use angular.copy? (Deep Copy)

I've been saving all the data received from services direct to local variable, controller, or scope. What I suppose would be considered a shallow copy, is that correct?

Example:

DataService.callFunction()
.then(function(response) {
  $scope.example = response.data;
});

Recently I was told to use angular.copy in order to create a deep copy.

$scope.example = angular.copy(response.data);

However, the deep copy information seems to be working in the same way when used by my Angular application. Are there specific benefits to using a deep copy (angular.copy) and can you please explain them to me?

This question is related to javascript angularjs deep-copy shallow-copy

The answer is


Use angular.copy when assigning value of object or array to another variable and that object value should not be changed.

Without deep copy or using angular.copy, changing value of property or adding any new property update all object referencing that same object.

_x000D_
_x000D_
var app = angular.module('copyExample', []);_x000D_
app.controller('ExampleController', ['$scope',_x000D_
  function($scope) {_x000D_
    $scope.printToConsole = function() {_x000D_
      $scope.main = {_x000D_
        first: 'first',_x000D_
        second: 'second'_x000D_
      };_x000D_
_x000D_
      $scope.child = angular.copy($scope.main);_x000D_
      console.log('Main object :');_x000D_
      console.log($scope.main);_x000D_
      console.log('Child object with angular.copy :');_x000D_
      console.log($scope.child);_x000D_
_x000D_
      $scope.child.first = 'last';_x000D_
      console.log('New Child object :')_x000D_
      console.log($scope.child);_x000D_
      console.log('Main object after child change and using angular.copy :');_x000D_
      console.log($scope.main);_x000D_
      console.log('Assing main object without copy and updating child');_x000D_
_x000D_
      $scope.child = $scope.main;_x000D_
      $scope.child.first = 'last';_x000D_
      console.log('Main object after update:');_x000D_
      console.log($scope.main);_x000D_
      console.log('Child object after update:');_x000D_
      console.log($scope.child);_x000D_
    }_x000D_
  }_x000D_
]);_x000D_
_x000D_
// Basic object assigning example_x000D_
_x000D_
var main = {_x000D_
  first: 'first',_x000D_
  second: 'second'_x000D_
};_x000D_
var one = main; // same as main_x000D_
var two = main; // same as main_x000D_
_x000D_
console.log('main :' + JSON.stringify(main)); // All object are same_x000D_
console.log('one :' + JSON.stringify(one)); // All object are same_x000D_
console.log('two :' + JSON.stringify(two)); // All object are same_x000D_
_x000D_
two = {_x000D_
  three: 'three'_x000D_
}; // two changed but one and main remains same_x000D_
console.log('main :' + JSON.stringify(main)); // one and main are same_x000D_
console.log('one :' + JSON.stringify(one)); // one and main are same_x000D_
console.log('two :' + JSON.stringify(two)); // two is changed_x000D_
_x000D_
two = main; // same as main_x000D_
_x000D_
two.first = 'last'; // change value of object's property so changed value of all object property _x000D_
_x000D_
console.log('main :' + JSON.stringify(main)); // All object are same with new value_x000D_
console.log('one :' + JSON.stringify(one)); // All object are same with new value_x000D_
console.log('two :' + JSON.stringify(two)); // All object are same with new value
_x000D_
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>_x000D_
_x000D_
<div ng-app="copyExample" ng-controller="ExampleController">_x000D_
  <button ng-click='printToConsole()'>Explain</button>_x000D_
</div>
_x000D_
_x000D_
_x000D_


I am just sharing my experience here, I used angular.copy() for comparing two objects properties. I was working on a number of inputs without form element, I was wondering how to compare two objects properties and based on result I have to enable and disable the save button. So I used as below.

I assigned an original server object user values to my dummy object to say userCopy and used watch to check changes to the user object.

My server API which gets me data from the server:

var req = {
    method: 'GET',
    url: 'user/profile/' + id,
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
}
$http(req).success(function(data) {
    $scope.user = data;
    $scope.userCopy = angular.copy($scope.user);
    $scope.btnSts=true;
}).error(function(data) {
    $ionicLoading.hide();
});

//initially my save button is disabled because objects are same, once something 
//changes I am activating save button

$scope.btnSts = true;
$scope.$watch('user', function(newVal, oldVal) {
    console.log($scope.userCopy.name);

    if ($scope.userCopy.name !== $scope.user.name || $scope.userCopy.email !== $scope.user.email) {
        console.log('Changed');
        $scope.btnSts = false;
    } else {
        console.log('Unchanged');
        $scope.btnSts = true;
    }    
}, true);

I am not sure but comparing two objects was really headache for me always but with angular.copy() it went smoothly.


I know its already answered, still i am just trying to make it simple. So angular.copy(data) you can use in case where you want to modify/change your received object by keeping its original values unmodified/unchanged.

For example: suppose i have made api call and got my originalObj, now i want to change the values of api originalObj for some case but i want the original values too so what i can do is, i can make a copy of my api originalObj in duplicateObj and modify duplicateObj this way my originalObj values will not change. In simple words duplicateObj modification will not reflect in originalObj unlike how js obj behave.

 $scope.originalObj={
            fname:'sudarshan',
            country:'India'
        }
        $scope.duplicateObj=angular.copy($scope.originalObj);
        console.log('----------originalObj--------------');
        console.log($scope.originalObj);
        console.log('-----------duplicateObj---------------');
        console.log($scope.duplicateObj);

        $scope.duplicateObj.fname='SUD';
        $scope.duplicateObj.country='USA';
        console.log('---------After update-------')
        console.log('----------originalObj--------------');
        console.log($scope.originalObj);
        console.log('-----------duplicateObj---------------');
        console.log($scope.duplicateObj);

Result is like....

    ----------originalObj--------------
manageProfileController.js:1183 {fname: "sudarshan", country: "India"}
manageProfileController.js:1184 -----------duplicateObj---------------
manageProfileController.js:1185 {fname: "sudarshan", country: "India"}
manageProfileController.js:1189 ---------After update-------
manageProfileController.js:1190 ----------originalObj--------------
manageProfileController.js:1191 {fname: "sudarshan", country: "India"}
manageProfileController.js:1192 -----------duplicateObj---------------
manageProfileController.js:1193 {fname: "SUD", country: "USA"}

I would say angular.copy(source); in your situation is unnecessary if later on you do not use is it without a destination angular.copy(source, [destination]);.

If a destination is provided, all of its elements (for arrays) or properties (for objects) are deleted and then all elements/properties from the source are copied to it.

https://docs.angularjs.org/api/ng/function/angular.copy


In that case, you don't need to use angular.copy()

Explanation :

  • = represents a reference whereas angular.copy() creates a new object as a deep copy.

  • Using = would mean that changing a property of response.data would change the corresponding property of $scope.example or vice versa.

  • Using angular.copy() the two objects would remain seperate and changes would not reflect on each other.


Javascript passes variables by reference, this means that:

var i = [];
var j = i;
i.push( 1 );

Now because of by reference part i is [1], and j is [1] as well, even though only i was changed. This is because when we say j = i javascript doesn't copy the i variable and assign it to j but references i variable through j.

Angular copy lets us lose this reference, which means:

var i = [];
var j = angular.copy( i );
i.push( 1 );

Now i here equals to [1], while j still equals to [].

There are situations when such kind of copy functionality is very handy.


When using angular.copy, instead of updating the reference, a new object is created and assigned to the destination(if a destination is provided). But there's more. There's this cool thing that happens after a deep copy.

Say you have a factory service which has methods which updates factory variables.

angular.module('test').factory('TestService', [function () {
    var o = {
        shallow: [0,1], // initial value(for demonstration)
        deep: [0,2] // initial value(for demonstration)
    }; 
    o.shallowCopy = function () {
        o.shallow = [1,2,3]
    }
    o.deepCopy = function () {
        angular.copy([4,5,6], o.deep);
    }
    return o;
}]);

and a controller which uses this service,

angular.module('test').controller('Ctrl', ['TestService', function (TestService) {
     var shallow = TestService.shallow;
     var deep = TestService.deep;

     console.log('****Printing initial values');
     console.log(shallow);
     console.log(deep);

     TestService.shallowCopy();
     TestService.deepCopy();

     console.log('****Printing values after service method execution');
     console.log(shallow);
     console.log(deep);

     console.log('****Printing service variables directly');
     console.log(TestService.shallow);
     console.log(TestService.deep);
}]);

When the above program is run the output will be as follows,

****Printing initial values
[0,1]
[0,2]

****Printing values after service method execution
[0,1]
[4,5,6]

****Printing service variables directly
[1,2,3]
[4,5,6]

Thus the cool thing about using angular copy is that, the references of the destination are reflected with the change of values, without having to re-assign the values manually, again.


Examples related to javascript

need to add a class to an element How to make a variable accessible outside a function? Hide Signs that Meteor.js was Used How to create a showdown.js markdown extension Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Summing radio input values How to execute an action before close metro app WinJS javascript, for loop defines a dynamic variable name Getting all files in directory with ajax

Examples related to angularjs

AngularJs directive not updating another directive's scope ERROR in Cannot find module 'node-sass' CORS: credentials mode is 'include' CORS error :Request header field Authorization is not allowed by Access-Control-Allow-Headers in preflight response WebSocket connection failed: Error during WebSocket handshake: Unexpected response code: 400 Print Html template in Angular 2 (ng-print in Angular 2) $http.get(...).success is not a function Angular 1.6.0: "Possibly unhandled rejection" error Find object by its property in array of objects with AngularJS way Error: Cannot invoke an expression whose type lacks a call signature

Examples related to deep-copy

Why and when to use angular.copy? (Deep Copy) How to deep copy a list? Copying an array of objects into another array in javascript How create a new deep copy (clone) of a List<T>? How to make a deep copy of Java ArrayList How do I copy a hash in Ruby? How do I clone a range of array elements to a new array? How to clone ArrayList and also clone its contents? What is the difference between a deep copy and a shallow copy?

Examples related to shallow-copy

Why and when to use angular.copy? (Deep Copy) How do I create a copy of an object in PHP? What is the difference between a deep copy and a shallow copy?