fablexis
fablexis

Reputation: 578

How to delete an element from an object inside a ng-repeat?

I'm trying to delete several elements from an object but I'm getting an error, this object is inside of a ng-repeat.

Error: Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: child in parent.beneficiaries, Duplicate key: undefined:undefined, Duplicate value: undefined

I made a simple script on plukr: https://plnkr.co/edit/W2C9ML4dEgJzqj6JeqWC?p=preview

My Controller:

angular
  .module("myApp", [])
  .controller("myCtrl", myCtrl);

  function myCtrl(){
    var vm = this;

    vm.classification = [
        {
          "name": "Favoritos",
          "beneficiaries":[
            {
              "idE": "1",
              "type": "Beneficiarios",
              "name": "Alexander Bueno",
              "selected": false
            },
            {
              "idE": "2",
              "type": "Beneficiarios",
              "name": "Lorena Torrealba",
              "selected": false
            },
            {
              "idE": "3",
              "type": "Beneficiarios",
              "name": "Fabián Pernía",
              "selected": false
            }
          ]
        },
        {
          "name": "Mis cuentas",
          "beneficiaries":[
            {
              "idE": "8",
              "type": "Cuentas",
              "name": "Corriente ...1234",
              "selected": false
            },
            {
              "idE": "9",
              "type": "Cuentas",
              "name": "Corriente ...9854",
              "selected": false
            },
            {
              "idE": "10",
              "type": "Cuentas",
              "name": "Ahorro ...9921",
              "selected": false
            }
          ]
        },
        {
          "name": "Terceros",
          "beneficiaries":[
            {
              "idE": "4",
              "type": "Beneficiarios",
              "name": "Alexander Ramírez",
              "selected": false
            },
            {
              "idE": "5",
              "type": "Beneficiarios",
              "name": "Vicente Delgado",
              "selected": false
            },
            {
              "idE": "6",
              "type": "Beneficiarios",
              "name": "Alexis Rodríguez",
              "selected": false
            },
            {
              "idE": "7",
              "type": "Beneficiarios",
              "name": "Ignacio Bueno",
              "selected": false
            }
          ]
        },
        {
          "name": "Tarjetas",
          "beneficiaries":[
            {
              "idE": "11",
              "name": "Visa ...6987",
              "selected": false
            },
            {
              "idE": "12",
              "name": "MasterCard ...7841",
              "selected": false
            }
          ]
        },
        {
          "name": "Servicios",
          "beneficiaries":[
            {
              "idE": "13",
              "name": "Electricidad de Caracas",
              "selected": false
            },
            {
              "idE": "14",
              "name": "C.A.N.T.V",
              "selected": false
            }
          ]
        }
      ];

    //function to delete elements
    vm.deleteElements = function(){
      for(var parent in vm.classification){
        for(var child in vm.classification[parent].beneficiaries){
          //if an element is selected then it will be deleted
          if(vm.classification[parent].beneficiaries[child].selected)
            //this fails if there are more than one element
            delete vm.classification[parent].beneficiaries[child]
        }
      }
    }
  }

My view:

<!DOCTYPE html>
<html ng-app="myApp">

  <head>
    <link data-require="[email protected]" data-semver="3.3.6" rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.css" />
    <script data-require="[email protected]" data-semver="1.3.14" src="https://code.angularjs.org/1.3.14/angular.js"></script>
    <script data-require="jquery@*" data-semver="2.2.0" src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
    <script data-require="[email protected]" data-semver="3.3.6" src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
    <link rel="stylesheet" href="style.css" />
    <script src="script.js"></script>
  </head>

  <body ng-controller="myCtrl as ctrl">
    <h1>Elements</h1>
    <a class="btn btn-danger" ng-click="ctrl.deleteElements();">Delete selected elements</a>

    <div class="well" ng-repeat="parent in ctrl.classification">
      <h3>{{parent.name}}</h3>
      <h5 ng-repeat="child in parent.beneficiaries">
        <input type="checkbox" ng-model="child.selected">{{child.name}}
      </h5>
    </div>

  </body>

</html>

So, what am I doing wrong?

Upvotes: 0

Views: 73

Answers (2)

a better oliver
a better oliver

Reputation: 26828

Using for ... in to loop through an array is not correct, as it doesn't only consider the elements of an array. Neither is deleting an element of an array with delete. That doesn't change the size of an array.

A rather simple solution is to filter the array:

vm.deleteElements = function(){
  vm.classification.forEach(function (classification) {
    classification.beneficiaries = classification.beneficiaries.filter(function(beneficiary) {
      return !beneficiary.selected;
    });
  });
}

Or if the browser supports ES6:

vm.deleteElements = function(){
  vm.classification.forEach( classification =>
    classification.beneficiaries = classification.beneficiaries.filter(beneficiary => !beneficiary.selected)
  );
}

Upvotes: 1

tenor528
tenor528

Reputation: 1175

It's asking you to have some unique identifier for each item in parent.beneficiaries. Here is the Angular page on it. If there is no unique id you can try track by $index or something like that. But you should be able to use this:

<h5 ng-repeat="child in parent.beneficiaries track by child.idE">

Upvotes: 1

Related Questions