angularでのng-repeatとtrack by
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)
関連
-
[解決済み】Angularjsのng-viewが動作しない。
-
[解決済み] 方法 $state.go()
-
[解決済み] AngularJSの.$uibModalとは何ですか?
-
[解決済み] シンプルなangularjsの日付入力
-
[解決済み] AngularJsでng-Cloakディレクティブを実際に使用する方法とは?
-
[解決済み] Apigee API へのリクエストで 401 レスポンスエラーが発生する
-
[解決済み] controllerAs "プロパティを使用する理由は何ですか?
-
処理されない例外が発生しました。Angular 実行中のプロジェクトで NGCC に失敗しました。
-
[解決済み] どのように$state.goにパラメータを追加しますか?
-
[解決済み] AngularJs .$setPristineでフォームをリセットする
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】TypeError: window.initMap is not a function
-
[解決済み] `ui-router` $stateParams vs. $state.params
-
[解決済み] angularJSのSTATEを理解する
-
[解決済み] オブジェクトと選択機能を備えたAngularJS BootstrapUI Typeahead
-
[解決済み] AngularJSのグローバル変数
-
[解決済み] AngularJSのシンプルな "Hello, world "が動作しない。
-
[解決済み] ag-gridの行の追加/削除
-
[解決済み] ng-repeat内で$indexを使用して、クラスを有効にしてDIVを表示するにはどうすればよいですか?
-
[解決済み] AngularJSのリソースプロミス
-
AngularJS がエラー $digest already in progress を報告する