orderBy $ filter阻止项目删除后的重复列表更新(拼接)

时间:2015-03-29 21:13:58

标签: javascript angularjs angularjs-filter angularjs-orderby

我有一个列表显示ng-repeat并按名称desc排序。

每个项目都有一个item-delete指令,其中包含$index,点击项目时,我使用index splice函数删除列表中的项目,然后我更新了列表 - 这不起作用!

根据我的调试结果,在指令内调用orderBy过滤器后会出现问题。如果我直接删除像scope.list.splice(index, 1)这样的项目,它可以工作,但删除的项目不正确,因为项目是按ng-repeat排序的,所以我必须以同样的方式订购它们,之后我可以执行正确删除。

解决方法是$emit新列表并更新控制器内的范围,但我不想这样做。经过测试和测试工作(见摘录)。

scope.$apply会遇到digest already in progress错误(因为此部分代码位于我的应用中的承诺内)&如果没有$timeout,则列表在工作时不会更新(例如,使用noFilter过滤器。)

*我正在使用一个指令从列表中删除一个项目因为我在项目点击(DOM更改,服务调用)上做了很多事情而且控制器不是那个地方(如果你是想我为什么不通过控制器这样做。)

另外,还有一个plnkr here

// JS

var APP = angular.module('APP', []);

APP.controller('Home', function($scope, $filter){
  var objData = {
    "1": {  id: 1, name: "Abc" },
    "2": {  id: 2,  name: "Bbc" },
    "3": {  id: 3, name: "Fea"  },
    "4": {  id: 4,  name: "Dbc" }
  };
  
  $scope.list = $filter('objToArr')(objData);
  
  //part of workaround...
  $scope.$on('listUpdate', function(evt, data){
    $scope.list = data;
  })
  
}); 

APP.directive('itemDelete', function($filter, $timeout){
  return{
    restrict: 'A',
    
    link: function(scope, el, attrs){
      var delIndex;
      attrs.$observe('itemDelete', function(val){
        delIndex = val;
      });
      
      angular.element(el).click(function(){
        console.log('deleting item index '+ delIndex);
        console.log('list length before ' + scope.list.length);
        
        //delete item from ng-repeat ordered list
        $timeout(function(){
          var listOrdered = $filter('orderBy')(scope.list, '-name'); //replace 'orderBy' with 'noFilter' -> it works, but removes wrong item!
          //var listOrdered = scope.list; // uncomment & comment line before this -> it works,  but removes wrong item!
          listOrdered.splice(delIndex,1);
          scope.list = listOrdered;
          
          //workaround...
          //scope.$emit('listUpdate', scope.list);
          
          console.log('list length after ' + scope.list.length);
        });
        
      });
      
    }
  }
})

APP.filter('objToArr', function(){
  return function(input){
    var arrData = [];
    angular.forEach(input, function(arr, key){
      arrData.push(arr);
    });
    
    return arrData;
  }
});

APP.filter('noFilter', function(){
  return function(input){
    return input;
  }
});
ul li{ display: block;  margin-bottom: 4px; background-color: #ccc; padding: 5px; }
ul{ list-style:none; }
<!DOCTYPE html>
<html ng-app="APP">

  <head>
    <script data-require="jquery@2.1.3" data-semver="2.1.3" src="http://code.jquery.com/jquery-2.1.3.min.js"></script>
    <script src="https://code.angularjs.org/1.3.15/angular.js" data-semver="1.3.15" data-require="angular.js@1.3.15"></script>
  </head>

  <body ng-controller="Home">
    <h4>Click on item - remove from list</h4>
    <ul>
      <li item-delete="{{ $index }}" ng-repeat="item in list | orderBy:'-name'">{{ item.name }}</li>
    </ul>
  </body>

</html>

1 个答案:

答案 0 :(得分:1)

问题出在这一行:

scope.list = listOrdered;

该行在chlid作用域上定义新的list属性,而不是更改实际列表,这是父作用域的属性。 (所以做范围。$ parent.list = listOrdered工作正常..)。

您可以通过将列表放在一个对象中来解决它,这将使引用保持同步:

$scope.objList = { list: $filter('objToArr')(objData) };

var listOrdered = $filter('orderBy')(scope.objList.list, '-name'); //replace 'orderBy' with 'noFilter' -> it works, but removes wrong item!
listOrdered.splice(delIndex,1);
scope.objList.list = listOrdered;

在您的HTML中:

<li item-delete="{{ $index }}" ng-repeat="item in objList.list | orderBy:'-name'">{{ item.name }}</li>

选中此plunker