试图操纵对象数组

时间:2017-03-22 15:24:20

标签: javascript angularjs

现在在我的记录中:

14.3,14.2和14.1属于Id = 30的部分。

我正在努力实现以下目标:

1)默认情况下,会选择前2个ID。如果用户尝试选择属于第30部分的id = 71,则不应允许用户选择id = 71,因为更高版本的第30部分已被选中,即id = 76。

2)现在,如果用户取消选中id = 77(33),则应允许用户检查id = 71,因为现在没有选择不同的部分,因此用户应该允许检查所有部分id = 30但是一旦用户选择了不同的部分,则应该取消选中下部。

我的代码问题:

1)当我取消选中16.1并尝试检查14.2时,我不允许检查它。我应该允许检查14.2,因为现在这里没有不同的部分。

2)默认情况下会检查16.1和14.3。现在当我检查15.1然后再检查14.1然后14.3取消选中这是错误的,因为14.3在部分id = 30中最高,所以我不能检查14.1。



  var app = angular.module('myApp', []);
        app.controller('myCtrl', function ($scope) {
            $scope.myArray = [
                 {
                     "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",
                 }
            ];

            $scope.checkItem = function (item) {
                if (item.selected) {
                    var index = $scope.myArray.map(m=>m.id).indexOf(item.id);
                    var previousPart = {};
                    for (var i = index - 1; i >= 0; i--) {
                        if ($scope.myArray[i].selected) {
                            previousPart = $scope.myArray[i];
                            break;
                        }
                    }
                    if (item.part != previousPart.part) {
                        for (var i = 0; i < $scope.myArray.length; i++) {
                            if (($scope.myArray[i].part == item.part && $scope.myArray[i].part != item.part)
                                && $scope.myArray[i].selected) {
                                $scope.myArray[i].selected = false;
                                break;
                            }
                        }
                    }
                    else
                        item.selected = false;



                }
            };
        });
&#13;
<!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>
&#13;
&#13;
&#13;

2 个答案:

答案 0 :(得分:3)

我会采取不同的方法。将一些逻辑分离到服务中可以帮助我保持代码更清晰。它将更易于维护,调试和测试。 fiddle

&#13;
&#13;
 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's 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);
   }

 })
&#13;
<!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>
&#13;
&#13;
&#13;

答案 1 :(得分:1)

我已经创建了一个解决方案,可以实现您的两个要点,并解决您上面提到的问题。

您需要仅在控制器中更新checkItem功能

$scope.checkItem = function(item) {
  if (item.selected) {
    var otherExists = $scope.myArray.filter(function(m) {
      return ((m.part != item.part) && m.selected);
    }).length;
    var selfExists = $scope.myArray.filter(function(m) {
      return ((m.part == item.part) && m.selected);
    }).length - 1;
    if (!!otherExists) {
      if (!!selfExists) {
        var selectedIsLower = $scope.myArray.filter(function(m) {
          return ((m.part == item.part) && (m.id > item.id) && m.selected);
        }).length;
        if (!!selectedIsLower) {
          item.selected = false;
        } else {
          $scope.myArray.filter(function(m) {
            return (m.part == item.part);
          }).forEach(function(m) {
            m.selected = false;
          });
          item.selected = true;
        }
      } else {
        item.selected = false;
        var allSelectedIds = [];
        var allSelected = $scope.myArray.filter(function(m) {
          return m.selected;
        });
        allSelected.map(m => m.part).forEach(function(a) {
          if (allSelectedIds.indexOf(a) < 0) { //skip duplicate id
            allSelectedIds.push(a);
          }
        });;
        if (allSelectedIds.length == 1) {
          var maxEle = {};
          allSelected.forEach(function(m, count) {
            if (maxEle.id) {
              (maxEle.id > m.id) && (m.selected = false);
            }
            maxEle.id = m.id;
            maxEle.count = count;
          });
        }
        item.selected = true;
      }
    }
  }
};

工作fiddle