Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trying to manipulate array of object

Now in my records :

14.3, 14.2 and 14.1 belongs to part with Id =30.

I am trying to achieve below:

1) By default first 2 ids will be selected.Now if user try to select id = 71 which belongs to part 30 then user should not be allowed to select id=71 because higher version of part 30 is already selected i.e id=76.

2) Now if user uncheck id = 77(33) then user should be allowed to check id=71 because now there is no different part selected so user should be allow to check all part with id = 30 but as soon as user select different part then lower part should be uncheck.

Problem with my code :

1) When I uncheck 16.1 and try to check 14.2 then I am not allowed to check it. I should allow to check 14.2 as now there is no different parts here.

2) 16.1 and 14.3 are check by default. Now when I check 15.1 and then again check 14.1 then 14.3 gets uncheck which is wrong as 14.3 is highest among part id=30 so I should not be able to check 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;



                }
            };
        });
<!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>
like image 566
Learning-Overthinker-Confused Avatar asked Mar 22 '17 15:03

Learning-Overthinker-Confused


People also ask

How do you modify an array of objects?

To update an object's property in an array of objects, use the map() method to iterate over the array. On each iteration, check if the current object is the one to be updated. If it is, modify the object and return the result, otherwise return the object as is.

How do you manipulate an array of objects in JavaScript?

Our function should search the first array for objects with the same "id" property that is present in the second array. Then our function should replace the "name" property of those objects with the corresponding "name" property of the second array's objects.

How do you access an array of objects?

A nested data structure is an array or object which refers to other arrays or objects, i.e. its values are arrays or objects. Such structures can be accessed by consecutively applying dot or bracket notation. Here is an example: const data = { code: 42, items: [{ id: 1, name: 'foo' }, { id: 2, name: 'bar' }] };

How do you modify a value in an array?

To change the value of all elements in an array:Use the forEach() method to iterate over the array. The method takes a function that gets invoked with the array element, its index and the array itself. Use the index of the current iteration to change the corresponding array element.


1 Answers

I would take a different approach. Separating some of the logic into a service helps me keep the code cleaner. It will be easier to maintain, debug and test. 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'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);
   }

 })
<!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>
like image 117
Petar Krivoshiev Avatar answered Oct 27 '22 16:10

Petar Krivoshiev