AngularJS订购后错误的$ index


92

我是Angular.js的新手,在排序数组和处理排序后的数据时遇到一些问题。

我有一个包含项目的列表,并希望按“ Store.storeName”对其进行排序,到目前为止,该列表仍然有效。但是在对数据进行排序之后,我的删除功能不再起作用。我认为那是因为排序后$ index错误,因此删除了错误的数据。

我该如何解决?在范围内而不是在视图中排序数据?怎么做?

这是一些相关的代码:

在视图中:

<tr ng-repeat="item in items | orderBy:'Store.storeName'">
                <td><input class="toggle" type="checkbox" ng-model="item.Completed"></td>
                <td>{{item.Name}}</td>
                <td>{{item.Quantity}} Stk.</td>
                <td>{{item.Price || 0 | number:2}} €</td>                
                <td>{{item.Quantity*item.Price|| 0 | number:2}} €</td>
                <td>{{item.Store.storeName}}</td> 
                <td><a><img src="img/delete.png" ng-click="removeItem($index)">{{$index}}</a></td>
            </tr>

在我的控制器中,我具有此删除功能,该功能应删除特定数据:

$scope.removeItem = function(index){
        $scope.items.splice(index,1);
    }

在视图中订购之前,这很好用。如果缺少重要的东西,请让我现在。

谢谢!

Answers:


140

取而代之或中继$index-如您所注意到的-将指向已排序/过滤后的数组中的索引,您可以将该项本身传递给removeItem函数:

<a><img src="img/delete.png" ng-click="removeItem(item)">{{$index}}</a>

removeItem使用indexOf数组方法修改该函数以找到索引,如下所示:

$scope.removeItem = function(item){
   $scope.items.splice($scope.items.indexOf(item),1);
}

1
@ pkozlowski.opensource你是个天才!您可以传递一个项目,而不是索引。谢啦。
good_evening

数组indexOf在Internet Explorer 8及更低版本中不可用。
彼得·赫德伯格

4
问题标题是在orderBy之后询问错误的$ index,此答案未解决。在某些情况下,您需要正确的$ index值(例如列表上的shift选择)。应用orderBy过滤器后,如何获得正确的$ index值?
ClearCloud8

您还可以通过执行以下操作从模板中的有序列表中创建一个新数组:“ ele inordered_array =(array | filter:filter | orderBy:order_by)”
Porlune

整齐!多谢兄弟。
CENT1PEDE '16

23

我开始学习角度问题,并面临类似的麻烦,并且根据@ pkozlowski-opensource的答案,我用类似

<a>
  <img src="img/delete.png" ng-click="removeItem(items.indexOf(item))">
  {{items.indexOf(item)}}
</a> 

1
这是最好的,而且如此简单,而不是创建自定义过滤器等。+1
Rafique Mohammed 2015年

1
这怎么是不正确的答案?这解决了我的问题
Cyrus Zei

19

我遇到了同样的问题,此主题中的其他答案不适合我的情况。

我已经通过自定义过滤器解决了我的问题:

angular.module('utils', []).filter('index', function () {
    return function (array, index) {
        if (!index)
            index = 'index';
        for (var i = 0; i < array.length; ++i) {
            array[i][index] = i;
        }
        return array;
    };
});

可以这样使用:

<tr ng-repeat="item in items | index | orderBy:'Store.storeName'">

然后在HTML中,您可以使用item.index代替$index

此方法适用于对象的集合。

请注意,此自定义过滤器应该是所有应用的过滤器列表中的第一个(orderBy等),它将index在该集合的每个对象中添加其他属性(名称是可自定义的)。


您能否详细说明为什么其他答案不适合您的情况?
pkozlowski.opensource

1
@ pkozlowski.opensource这要干净得多。还取决于可以附加哪些事件,以及indexOf中项目的复杂性要高得多。$scope.items.splice($scope.items.indexOf(item),1);对于重复项,也将无法正常工作。
马丁

1
@martin,您应该使用实数备份您对性能的要求。过滤器具有在每个 $ digest循环上执行的巨大缺点,因此我认为它对性能没有帮助...
pkozlowski.opensource

@ pkozlowski.opensource是的,每个$ digest循环运行两次。重要的是“取决于可能附加的事件”,当您无法控制速率时,性能就很重要,例如,不受限制的滚动事件-我知道的极端情况。
马丁

@mile好吧,我确实有重复项,这就是我想要的,有点遗憾Angular不跟踪或$变量中的原始索引。我试过(key, item) in items了,也不行。(密钥未保留为原始密钥)
Rouche

4

试试这个:

$scope.remove = function(subtask) {

    var idx = $scope.subtasks.indexOf(subtask),
        st = $scope.currentTask.subtasks[idx];

    // remove from DB
    SubTask.remove({'subtaskId': subtask.id});

    // remove from local array
    $scope.subtasks.splice(idx,1);

}

您可以在我的博客中的此条目中找到详细的说明。


2

万一有人需要使用$index,可以给已排序/过滤后的数组起一个名字:

<tr ng-repeat="item in sortedItems = (items | orderBy:'Store.storeName') track by $index">

在这里查看我的答案。


我认为如果没有详细信息,这个答案很好。我认为hmk的意思是,如上所述,一旦过滤列表被搁置一旁,就可以针对它使用索引(即“ sortedItems [$ index]”)来检索所需的条目。
杰里米瑟夫18'Dec

1

我只会发表评论,但我没有“声誉”。

mile的解决方案正是我所需要的。要回答pkozlowski.opensource的问题:当您嵌套了ngRepeats,动态列表(例如,您允许删除)或两者都嵌套(这是我的情况)时,使用$index将不起作用,因为这将是后端的错误索引排序后ngInit用于缓存值的数据也不起作用,因为当列表更改时不会重新评估它。

请注意,mile的解决方案允许通过传递参数来自定义索引属性名称 <tr ng-repeat="item in items | index:'originalPosition' | orderBy:'Store.storeName'">

我的调整版本:

.filter( 'repeatIndex', function repeatIndex()
{
// This filter must be called AFTER 'filter'ing 
//  and BEFORE 'orderBy' to be useful.
    return( function( array, index_name )
    {
        index_name = index_name || 'index';
        array.forEach( function( each, i )
        {each[ index_name ] = i;});
        return( array );
    });
})
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.