I know for a fact there is something pretty obvious here that I am completely missing, so your help is greatly appreciated.
I have a feature that provides two dropdowns. They contain the same data (the feature allows a trade between two people, the people is the data), but I want them each to get their own copy of said data.
Another part of this feature is that by picking Person A in the first dropdown, I want to disable Person A in the second dropdown, and vice versa, so I have the ng-options tag paying attention to a disabled property on the object.
The issue I have is that even with using a method such as Lodash's clone to properly create a "new" array upon first time assignment, every time I access Person A in ONE array (and specifically do NOT access the other array) invariably I am seeing that when I touch Person A, that object is updated in BOTH arrays, which has me flustered.
This feels like a down-to-the-metal, barebones Javascript issue (standard PEBCAK, I feel like I'm clearly misunderstanding or straight up missing something fundamental), maybe with a bit of AngularJS rendering-related fun-ness involved, but... What gives?
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 />
I threw everything relevant on $scope just for the sake of getting it working and illustrating the issue, but here's how it goes:
- On init, I grab the array, then clone a copy for each dropdown
- When each dropdown changes the model property (the object ID), I have a scope listener then call a method to handle disabling the selected object/person in the OPPOSITE list
- Within this method, I determine which of the two lists/arrays to iterate through and mark the disabled object
- At the end of this method, I do a simple console.log call to check the value of a given object. For quick-and-dirty simplicity, I just grab item at index 0 .
- What I expected: one object have a
disabledvalue oftrue, and the opposite object to havefalse. What I see: they both havetrue(assuming you select the first "real" item in the dropdown)
What's the deal? How big of an idiot am I being?