Как удалить элемент из объекта внутри ng-repeat?

Я пытаюсь удалить несколько элементов из объекта, но получаю сообщение об ошибке, этот объект находится внутри ng-repeat.

Ошибка: Дубликаты в повторителе не допускаются. Используйте выражение «track by», чтобы указать уникальные ключи. Повторитель: дочерний в parent.beneficiaries, Дублирующий ключ: не определено: не определено, Повторяющееся значение: не определено

Я сделал простой скрипт на plukr: https://plnkr.co/edit/W2C9ML4dEgJzqj6JeqWC?p=preview

Мой контроллер:

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]
        }
      }
    }
  }

Мой взгляд:

<!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>

Итак, что я делаю неправильно?


person fablexis    schedule 22.02.2016    source источник
comment
beneficiaries — это массив, поэтому child in vm.classification[parent].beneficiaries для начала неверно. Как и delete vm.classification[parent].beneficiaries[child].   -  person a better oliver    schedule 22.02.2016
comment
Хорошо, какая правильная форма для этого? Если я добавлю к этому коду track by $index внутри <h5 ng-repeat="child in parent.beneficiaries>, он сработает   -  person fablexis    schedule 22.02.2016


Ответы (2)


Использование for ... in для перебора массива некорректно, так как оно учитывает не только элементы массива. Также не удаляется элемент массива с delete. Это не меняет размер массива.

Довольно простое решение — отфильтровать массив:

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

Или, если браузер поддерживает ES6:

vm.deleteElements = function(){
  vm.classification.forEach( classification =>
    classification.beneficiaries = classification.beneficiaries.filter(beneficiary => !beneficiary.selected)
  );
}
person a better oliver    schedule 22.02.2016
comment
Отличный ответ! Очень ясно! Спасибо! Это работает очень хорошо! - person fablexis; 22.02.2016

Он просит вас иметь уникальный идентификатор для каждого элемента в parent.beneficiaries. Вот страница Angular. Если уникального идентификатора нет, вы можете попробовать track by $index или что-то в этом роде. Но вы должны быть в состоянии использовать это:

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

person tenor528    schedule 22.02.2016
comment
с ‹h5 ng-repeat=child в отслеживании parent.beneficiaries от child.idE› это не работает :( - person fablexis; 22.02.2016
comment
Это работает, если использовать трек по $index! Спасибо, но у меня другой вопрос, как удалить записи, которые были удалены? - person fablexis; 22.02.2016