AngularjsはorderBy後の$ 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);
    }

これは、ビューで注文する前にうまく機能します。重要なものが足りない場合は、すぐにお知らせください。

ありがとう!

回答:


140

代わりに、またはリレー$index-これは-お気づきのように-並べ替え/フィルターされた配列のインデックスを指すため、アイテム自体をremoveItem関数に渡すことができます。

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

次のように配列removeItemindexOfメソッドを使用してインデックスを見つけるように関数を変更します。

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

1
@ pkozlowski.opensourceあなたは天才です!インデックスではなくアイテムを渡すことができます。ありがとう。
good_evening 2014

配列indexOfは、Internet Explorer 8以下では使用できません。
Peter Hedberg 2014年

4
質問のタイトルは、orderByの後の間違った$ indexについて尋ねていますが、この回答では対処しません。正しい$ index値が必要な場合があります(リストのシフト選択など)。orderByフィルターが適用された後、どのようにして正しい$ index値を取得しますか?
ClearCloud8

テンプレート内の順序付きリストから、次のようにして新しい配列を作成することもできます: "ele in ordered_array =(array | filter:filter | orderBy:order_by)"
Porlune

きちんと!ありがとう兄貴。
CENT1PEDE 2016

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 2014

1
@ pkozlowski.opensourceこれははるかにきれいです。また、添付できるイベントや、indexOfの項目の複雑さによってはるかに効率的になります。また$scope.items.splice($scope.items.indexOf(item),1);、重複するアイテムに対しては期待どおりに機能しません。
マーティン2014年

1
@martinでは、パフォーマンスに関する主張を実数でバックアップする必要があります。フィルターは$ digestサイクルごとに実行されるという大きなデメリットがあるため、パフォーマンスに役立つとは思いません...
pkozlowski.opensource '18

@ pkozlowski.opensourceこれは事実であり、$ digestサイクルごとに2回実行されます。重要なことは「アタッチできるイベントに依存する」ことです。たとえば、スロットルされていないスクロールイベントなど、レートを制御できない場合、パフォーマンスが重要になります-極端なケースです。
マーティン2014年

@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]」)を使用して目的のエントリを取得できることです。
Jeremythuff、

1

私はコメントを残しただけですが、「評判」はありません。

マイルの解決策は、まさに私が必要としていたものでもあります。pkozlowski.opensourceの質問に答える:ネストされngRepeatた、動的リスト(たとえば、削除を許可する場所)、またはその両方(私の場合)がある場合$index、バックエンドのインデックスが正しくないため、使用できませんソートしてngInit値をキャッシュするために使用した後のデータも、リストが変更されたときに再評価されないため機能しません。

マイルのソリューションでは、パラメータを渡すことにより、添付されたインデックスプロパティ名をカスタマイズできることに注意してください <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 );
    });
})
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.