Ответ 1
Я бы выбрал другой подход. Разделение некоторой логики на службу помогает мне очищать код. Будет легче поддерживать, отлаживать и тестировать. fiddle
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope, myCollection) {
$scope.myArray = myCollection.items;
// Call function every time an item was checked
$scope.checkItem = function(item) {
// Remap collection items before and after
myCollection.mapCheckedItems();
// Do something with the user interaction only if there are
// different selected parts by definition
if (item.selected && myCollection.selectedPartsOnly.length > 1) {
// Iterate through the selected parts
myCollection.selectedPartsOnly.map(part => {
// Get the array of items belonging to the exact part number
var map = myCollection.selectedPartsMap[part];
for (var j = map.length - 1; j > 0; j--) {
// By definition deselect all but the highest version.
// Happens if different part numbers selected simultaneously
map[j].selected = false;
}
})
}
// Recalculate collection map to keep it up to date with the
// items' array
myCollection.mapCheckedItems();
};
});
app.service('myCollection', function() {
// Init the collection object
var self = {};
// Function to calculate and map items' dependencies
self.mapCheckedItems = mapCheckedItems;
// This holds a list of the selected unique part numbers
// Used to determine needed action easier. By definition if only
// one part number is selected and used to iterate through the map
self.selectedPartsOnly = [];
// This is the important dictionary where the part numbers is mapped
// to its child items. Easy access to items grouped by a part number
self.selectedPartsMap = {};
// The actual array definition
self.items = [{
"id": 77,
"selected": true,
"part": 33,
"name": "16.1",
}, {
"id": 76,
"part": 30,
"selected": true,
"name": "14.3",
}, {
"id": 71,
"part": 30,
"selected": false,
"name": "14.2",
}, {
"id": 70,
"part": 31,
"selected": false,
"name": "15.1",
}, {
"id": 69,
"part": 30,
"selected": false,
"name": "14.1",
}, {
"id": 68,
"part": 29,
"selected": false,
"name": "13.1",
}, {
"id": 55,
"part": 26,
"selected": false,
"name": "12.1",
}, {
"id": 54,
"part": 25,
"selected": false,
"name": "11.2",
}, {
"id": 53,
"part": 25,
"selected": false,
"name": "11.1",
}];
// Init the helpers once on start. This will be executed only once
mapCheckedItems();
// Return the service object to be accessed from the controller
return self;
// This function will create and update the objects mapping
function mapCheckedItems() {
// Reset the helpers
self.selectedPartsOnly = [];
self.selectedPartsMap = {};
// Now we iterate through the selected items.
self.items
.filter(item => item.selected)
.map(item => {
// Map every selected item directly to one part number
mapSelectedParts(item);
// Determine what part numbers are in use.
mapSelectedPartsOnly(item.part);
})
}
function mapSelectedPartsOnly(part) {
if (self.selectedPartsOnly.indexOf(part) == -1)
self.selectedPartsOnly.push(part);
}
function mapSelectedParts(item) {
if (!self.selectedPartsMap[item.part])
self.selectedPartsMap[item.part] = [];
self.selectedPartsMap[item.part].push(item);
}
})
<!DOCTYPE html>
<html ng-app="myApp" ng-controller="myCtrl">
<head>
<title></title>
<meta charset="utf-8" />
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
</head>
<body>
<div ng-repeat="item in myArray">
<input ng-model="item.selected" ng-click="checkItem(item)" type="checkbox" />{{ item.name }}
</div>
</body>
</html>