【发布时间】:2019-05-22 21:46:24
【问题描述】:
事实上,我知道这里有一些非常明显的东西我完全遗漏了,因此非常感谢您的帮助。
我有一个提供两个下拉菜单的功能。它们包含相同的数据(该功能允许两个人之间进行交易,人就是数据),但我希望他们每个人都获得自己的数据副本。
此功能的另一部分是通过在第一个下拉列表中选择人 A,我想在第二个下拉列表中禁用人 A,反之亦然,所以我有 ng-options 标记注意 disabled 属性在物体上。
我遇到的问题是,即使使用 Lodash 的 clone 之类的方法在第一次分配时正确创建一个“新”数组,每次我在一个数组中访问人 A 时(特别是不要访问另一个array) 总是我看到当我触摸 Person A 时,该对象在两个数组中都更新了,这让我很慌张。
这感觉像是一个彻头彻尾的、准系统的 Javascript 问题(标准 PEBCAK,我觉得我显然误解了或直接遗漏了一些基本的东西),也许有一点 AngularJS 渲染相关的乐趣参与其中,但是...什么给出了?
angular.module('myApp', [])
.controller('weirdDataController', function($scope) {
$scope.$watch('manager1_id', () => {
if (angular.isDefined($scope.manager1_id) && parseInt($scope.manager1_id, 10) > 0) {
$scope._disableManagerInOtherDropdown(false, $scope.manager1_id);
}
});
$scope.$watch('manager2_id', () => {
if (angular.isDefined($scope.manager2_id) && parseInt($scope.manager2_id, 10) > 0) {
$scope._disableManagerInOtherDropdown(true, $scope.manager2_id);
}
});
$scope._gimmeFakeData = () => {
return [{
manager_id: 1,
manager_name: 'Bill',
disabled: false
},
{
manager_id: 2,
manager_name: 'Bob',
disabled: false
},
{
manager_id: 3,
manager_name: 'Beano',
disabled: false
},
{
manager_id: 4,
manager_name: 'Barf',
disabled: false
},
{
manager_id: 5,
manager_name: 'Biff',
disabled: false
},
];
};
const data = $scope._gimmeFakeData();
$scope.firstManagers = _.clone(data);
$scope.secondManagers = _.clone(data);
$scope._disableManagerInOtherDropdown = (otherIsFirstArray, managerId) => {
const disableManagers = manager => {
manager.disabled = manager.manager_id === managerId;
};
if (otherIsFirstArray) {
$scope.firstManagers.forEach(disableManagers);
} else {
$scope.secondManagers.forEach(disableManagers);
}
console.log('Is the first item the same??', $scope.firstManagers[0].disabled === $scope.secondManagers[0].disabled);
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<div ng-app="myApp" ng-controller="weirdDataController">
<div class="col-xs-12 col-sm-6">
<select class="form-control" ng-model="manager1_id" ng-options="manager.manager_id as manager.manager_name disable when manager.disabled for manager in firstManagers track by manager.manager_id">
<option value="" disabled="disabled">Choose one manager</option>
</select>
<select class="form-control" ng-model="manager2_id" ng-options="manager.manager_id as manager.manager_name disable when manager.disabled for manager in secondManagers track by manager.manager_id">
<option value="" disabled="disabled">Choose another manager</option>
</select>
</div>
</div>
<br /><br />
我把所有相关的东西都放在$scope 上,只是为了让它工作并说明问题,但事情是这样的:
- 在初始化时,我抓取数组,然后为每个下拉列表克隆一个副本
- 当每个下拉列表更改模型属性(对象 ID)时,我有一个范围侦听器,然后调用一个方法来处理禁用 OPOSITE 列表中选定的对象/人员
- 在此方法中,我确定要遍历两个列表/数组中的哪一个并标记禁用的对象
- 在此方法结束时,我执行了一个简单的 console.log 调用来检查给定对象的值。为了快速简单起见,我只抓取索引 0 处的项目。
- 我所期望的:一个对象的
disabled值为true,而另一个对象的值为false。我所看到的:他们都有true(假设您选择下拉列表中的第一个“真实”项目)
有什么关系?我到底有多白痴?
【问题讨论】:
-
您已经复制了数组,但它们都引用了相同的对象实例。因此,在一个数组中改变对象将导致另一个数组中的相同突变,因为它们是对相同对象的引用。
-
我是否从根本上误解了
clone的工作原理?当我第一次启动这个功能时,我确实只是在做简单的赋值,所以它是一个共享数组,但后来我开始使用clone来解决这个问题。让我再去看看文档看看。 -
是的,你想要
_.cloneDeep()。 -
顺便说一句,我认为帕特里克在这里一针见血,虽然 cloneDeep 解决了问题,但问题最终是在功能布局方面有点代码味道.我备份并重新考虑了该功能的设计方式(我自己,4 年前?)并相应地对其进行了更新,以更好地处理 UI 和底层数据之间的分离。感谢所有的帮助!
-
@Mattygabe,如果您自己发布一个答案会很有用,这样这个问题......好吧,有一个答案;-) 回答您自己的问题是完全可以的。跨度>
标签: javascript arrays angularjs ecmascript-6 lodash