1. ホーム
  2. angularjs

angularでのng-repeatとtrack by

2022-02-24 14:47:36
<ブロッククオート

ng-repeatでjavascriptの配列を反復するとき、angularjsは配列に重複した要素があるとエラーを報告します。

<スパン 数値や文字列のような基本的なデータ型では、そのidはそれ自身の値です。したがって、2つの同じ数値が配列の中に存在することは許されません。このエラーを回避するためには、式によって独自のトラックを定義する必要があります。

// 事業者は独自のIDを生成する
item.idによるアイテムトラック内のアイテム

//ループのインデックス変数 $index を使用します。
item in items track by $index

Error: [ngRepeat:dupes] このエラーヒントは、対象のケースに特有のもので、インデックスグループに同じ番号が2つ以上あることを意味します。 ngRepeatは、コレクション内に同じIdを持つ2つのオブジェクトを許可しません。

簡単な動作の一覧

まず、完全で有効な ng-repeat の例です。

<ul ng-controller="ListCtrl">
  <li ng-repeat="item in items">
    {
{item.name}}
    <button ng-click="remove($index)">remove</button>
  </li>
</ul>

対応するコントローラは以下の通りです。

app.controller('ListCtrl', ['$scope', function($scope) {
  //items come from somewhere, from where doesn't matter for this example
  $scope.items = getItems();

  $scope.remove = function(index) {
    var item = $scope.items[index];
    removeItem(item);
  };
}]);

問題なさそうでしょう?このコードも特に注目すべき点はありません。

フィルタを追加する

次に、リストにフィルターを追加するという、ちょっとした変更を加えてみましょう。これはリストが長い場合によくあることで、例えばユーザーが検索を行えるようにするためです。

便宜上、このような場合、(1)のように  searchFilter  を使用して、リスト内のレコードを検索します。

<ul ng-controller="ListCtrl">
  <li ng-repeat="item in items | searchFilter">
    {
{item.name}}
    <button ng-click="remove($index)">remove</button>
  </li>
</ul>

コントローラのコードはそのままです。やはり問題なさそうですよね?

実は、そこにバグが隠れているんです。黙っていても見つかる?もしできたら、あなたはもうAngularの専門家です。

を使用しないようにしてください。  $index

実はバグはコントローラの中にあるのです。

$scope.remove = function(index) {
  var item = $scope.items[index];
  removeItem(item);
};

ここでは index パラメータを使用していますが、ここでバグに遭遇しました。フィルタリングされたインデックスが元のリストのインデックスと一致しないのです。

幸いなことに、この問題を回避する非常に簡単な方法があります。 $index 代わりに、実際のアイテムオブジェクトを使用します。

<ul ng-controller="ListCtrl">
  <li ng-repeat="item in items | searchFilter">
    {
{item.name}}
    <button ng-click="remove(item)">remove</button>
  </li>
</ul>

コントローラは以下のとおりです。

$scope.remove = function(item) {
  removeItem(item);
};

ただし  remove($index)  から  remove(item) を修正し、さらに  $scope.remove  関数を使用して、渡されたオブジェクトを直接操作することができます。

この小さな変更により、先程のバグは完全に回避されました。

問題と解決策をより分かりやすく説明するために、対話型の例をご覧ください。

ここから何がわかるの?

最初の教訓は、もちろん  $index  は、使い方によってはバグが発生する可能性があるので、少し注意が必要です。

2つ目の教訓は、このようなパターンはもっと良い方法で行うことができ、ある種のバグを完全に回避することができるということを覚えておくことです。を使わないことを強くお勧めします。  $index そして、この単純な発想の転換から、コードの多くのバグを減らすことができるのです。

3つ目の教訓は、「テストは必ずしも有用ではない」ということです。自動化されたテストで十分な状況をカバーしていても、特定の入力に依存する状況でのバグを見逃すことはよくあることです。フィルターを使ってテストしても、バグそのものが表示されるとは限りません。

4つ目の教訓は、抽象化を壊さないこと -- これは見落としがちなことです。理論的には  $index  は  ng-repeat  テンプレート変数"が作成されます。これはrepeatブロックの中でのみ意味を持ちます(正しく動作します)。その値を外部に渡すと、文脈を失い、もはや有効ではなくなります。もし本当にrepeatの外で動作させたいのであれば、コントローラ内でもフィルタをかける必要があり、あまり必要のない反復的なコードが必要になります。ありがたいことに、この記事で紹介したパターンを使えば、この状況を回避することができます。


エヌジーリピート

定義と使用方法

エヌジーリピート  ディレクティブは、HTML 要素を指定された回数だけループさせるために使用されます。

コレクションは、配列またはオブジェクトでなければならない。


シンタックス

< エレメント ng-repeat=。 " " > < / エレメント >


パラメータ値

<テーブル 価値 商品説明 この式は、コレクションをループさせる方法を定義しています。
式のインスタンスルール。
x in records


(key, value) in myObj

x in records track by $id(x)