orderBy $filter 在项目删除(拼接)后阻止 ng-repeat 列表更新
orderBy $filter blocks ng-repeat list update after item deletion (splice)
我有一个用 ng-repeat 显示并按名称 desc 排序的列表。
每个项目都有一个 item-delete
指令,它包含 $index
并且在项目单击时我使用给定的 index
和 splice
函数从列表中删除该项目然后我更新列表 - 这不起作用!
根据我的调试结果,问题发生在 orderBy
过滤器在指令内部调用之后。如果我像这样 scope.list.splice(index, 1)
直接删除项目,它会起作用,但删除的项目不是正确的项目,因为项目是由 ng-repeat 订购的,所以我必须以相同的方式订购它们,然后我可以执行正确删除。
解决方法是 $emit
新列表并更新控制器内的范围,但我不想这样做。测试和工作(见片段)。
A 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>
问题出在这一行:
scope.list = listOrdered;
该行在 chlid 作用域上定义了一个新的 list
属性,而不是更改实际列表,它是父作用域的 属性。 (这样做 scope.$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
我有一个用 ng-repeat 显示并按名称 desc 排序的列表。
每个项目都有一个 item-delete
指令,它包含 $index
并且在项目单击时我使用给定的 index
和 splice
函数从列表中删除该项目然后我更新列表 - 这不起作用!
根据我的调试结果,问题发生在 orderBy
过滤器在指令内部调用之后。如果我像这样 scope.list.splice(index, 1)
直接删除项目,它会起作用,但删除的项目不是正确的项目,因为项目是由 ng-repeat 订购的,所以我必须以相同的方式订购它们,然后我可以执行正确删除。
解决方法是 $emit
新列表并更新控制器内的范围,但我不想这样做。测试和工作(见片段)。
A 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>
问题出在这一行:
scope.list = listOrdered;
该行在 chlid 作用域上定义了一个新的 list
属性,而不是更改实际列表,它是父作用域的 属性。 (这样做 scope.$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