0

I declared a function (named "insertTstData") outside any angular scope (it's not even inside a controller or anything) and when I call it from another function (named "save") inside a controller (named "remark"), it modifies a local variable and the change gets reflected back to the variable inside the scope and every other variable with the same content (even the ones not connected to it in any way!).

It's so absurd I don't even know how to explain it without telling you the whole flow.

So, first off i use the $http service to get a JSON configuration file and create a scope variable to store it (we're now in the "main" controller, which is the parent of the "remark" one, in which the bug happens):

 $http.get(path + 'remarkConfig.json')
        .then(function (response) {
            //change fields
            $scope.remark = response.data; //this variable will get used later on
            $scope.dummy = response.data; //this variable will be changed even if not used anymore
});

These variables are array of objects, but for simplicity let's say they're object with two properties:

{"p1":"PROP ONE", "p2": "PROP TWO"}

now, i have a button inside the "remark" controller which calls the function save and passes $scope.remark to it:

<md-button class="amaButton md-raised" ng-click="save(data, remark)" aria-label="save">{{translate.save}}</md-button>

here's the function save inside the "remark" controller's scope (in which is injected the "main" scope):

$scope.save = function (data, remarks) {
    console.log($scope.dummy);
    console.log($scope.remark);
    console.log(remarks);
    //all these variables still contain the original values
    var originalRemarks = {};    //another dummy variable, just to be sure
    originalRemarks.codes = remarks;
    //insert TSTs into data, formatting <>-like remarks
    var response = insertTstData(data, $scope.tst, remarks);   //this is the function which wreaks havoc, I pass to it the variable remarks by value (or at least I thought so)
    console.log($scope.dummy);
    console.log($scope.remark);
    console.log(remarks);
    console.log(originalRemarks.codes);
    //they ALL changed!
}

Now, let's see the function which causes the bug (remember, it's outside any controller/scope/whatever). All the function does is changing a local variable (set = to remarks) according to the other two arguments and returns a response:

function insertTstData(data, tst, remarks) {
    var rem = remarks; 
    rem.p1="";
    var response={"data": data, "remarks": rem};
    return response;
}
//after these function returns, every variable's p1 is set to an empty string!

I'm totally sure this is the point in which it happens and these variables aren't changed ANYWHERE else in the code (debugged it for hours yesterday to no avail).

What am I doing wrong? Are they all pointers to the same value due to some strange mechanic I'm not aware of?

Kitra
  • 13
  • 6

3 Answers3

1

That is the difference between a shallow and a deep copy of the variable. In javascript a simple assignment of an object (not a primitive type) is always made by reference (shallow copy), that means for example

var remarks = {"p1":"PROP ONE", "p2": "PROP TWO"}
var rem = remarks; //the assignment

rem will hold a reference to the object remarks and every change to a field of remarks will reflect on a change on rem and viceversa. if you want to create two distint objects (deep copy) you should use angular.copy

var rem = angular.copy(remarks)

In such way the two variables will hold two different references to two difference area in memory, thus two different objects.

enter image description here

Karim
  • 8,454
  • 3
  • 25
  • 33
0

When ever you create a variable rem (var rem = remark), javaScript creates a reference to the original object, instead of making a clone of it. So, even if you modify rem, it will make the changes in the parent object.

I suggest you to use clone() method, to create a duplicate object.

Follow through this link for creating a clone of an object in js

Community
  • 1
  • 1
Vamsi
  • 672
  • 4
  • 16
  • It actually is an array of objects, but this actually worked! I never thought of that since I tried to do weird things like – Kitra Oct 20 '16 at 09:47
  • It actually is an array of objects, but this actually worked! I never thought of that since I tried to do weird things like var rem = []; for (var i = 0; i < remarks.length; i++) rem[i] = remarks[i]; – Kitra Oct 20 '16 at 09:49
0

You can also use angular.copy(remarks) to create a deep copy of the object which can be either object or array.

Brian Liu
  • 331
  • 2
  • 6