Angular weirdness: how can one object attribute change an attribute on two different objects?

巧了我就是萌 提交于 2021-02-05 06:09:49

问题


I'm building a website using Angularjs in which I've got a list of objects:

$scope.fieldsToShow = [
    {
        "fields": {},
        "type": "LOGGED_IN"
    },
    {
        "fields": {},
        "type": "PERSONAL",
        "user": 2,
        "name": "Rick Astley"
    }
];

I then select one of the objects into a variable:

var $scope.currentObject = $scope.fieldsToShow[1];

to let the user change it using the some checkboxes:

<input ng-model="currentObject.fields.a" type="checkbox">

which changes both $scope.currentObject:

{
    "fields": {
        "a": true
    },
    "type": "PERSONAL",
    "user": 2,
    "name": "Rick Astley"
}

and the original object in $scope.fieldsToShow:

$scope.fieldsToShow = [
    {
        "fields": {},
        "type": "LOGGED_IN"
    },
    {
        "fields": {
            "a": true
        },
        "type": "PERSONAL",
        "user": 2,
        "name": "Rick Astley"
    }
];

I then change the $scope.currentObject to the first object in the array:

$scope.currentObject = $scope.fieldsToShow[0];

and I click the checkbox again. As expected this also adds "a": true to the fields object of the first object in the $scope.fieldsToShow list. So far so good.

I now want to add an object within the fields object. So I created another checkbox:

<input ng-model="currentObject.fields.anInnerObject.val" type="checkbox">

I then change to the PERSONAL object again ($scope.currentObject = $scope.fieldsToShow[1];) and click the checkbox. As expected this changes both the $scope.currentObject:

{
    "fields": {
        "anInnerObject": {
            "val": true
        }
    },
    "type": "PERSONAL",
    "user": 2,
    "name": "Rick Astley"
}

and the original object in $scope.fieldsToShow:

$scope.fieldsToShow = [
    {
        "fields": {},
        "type": "LOGGED_IN"
    },
    {
        "fields": {
            "anInnerObject": {
                "val": true
            }
        },
        "type": "PERSONAL",
        "user": 2,
        "name": "Rick Astley"
    }
];

I then change to the LOGGED_IN object again ($scope.currentObject = $scope.fieldsToShow[0];) and click the checkbox again. And here is where it gets tricky. As expected it changes the $scope.currentObject:

{
    "fields": {
        "anInnerObject": {
            "val": true
        }
    },
    "type": "LOGGED_IN",
}

it also changes the original object in $scope.fieldsToShow (still as expected), BUT it ALSO changes the value of "anInnerObject" in the PERSONAL object to the boolean true:

$scope.fieldsToShow = [
    {
        "fields": {
            "anInnerObject": {
                "val": true  // This changed, which I understand
            }
        },
        "type": "LOGGED_IN"
    },
    {
        "fields": {
            "anInnerObject": true  // BUT WHY this value also change? And why did it become true?
        },
        "type": "PERSONAL",
        "user": 2,
        "name": "Rick Astley"
    }
];

How in the world can this happen?! I've been banging my head against the wall for hours, tried a million things and asked a colleague for help, but I simply can't find why this behaves like it does?

Does anybody know how this can happen? All tips are welcome!


回答1:


You need to understand that both both $scope.currentObject and the original object in $scope.fieldsToShow the same object. Both are just references to the same memory location. This is how references to non-primitive types work in Javasript.

If you want to have truly separate different object you need to clone it before using:

var $scope.currentObject = angular.copy($scope.fieldsToShow[1]);


来源:https://stackoverflow.com/questions/33752295/angular-weirdness-how-can-one-object-attribute-change-an-attribute-on-two-diffe

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!