ngRepeat で Duplicate Key in Repeater エラー

2015年2月18日 16:06

AngularJS で繰り返し処理を実現する ngRepeat ディレクティブは、基本的に以下のように使用される。

<ul>
    <li ng-repeat="user in ['John', 'Paul', 'George', 'Ringo']">{{ user }}</li>
</ul>

ここで注意すべきは、コレクション内で識別されている要素が DOM に紐付くという点だ。つまり、この例で言えば、ng-repeat によって展開された 4 つの DOM 要素には、与えられたコレクション(この場合は配列)の各々の要素が紐付けられる。これは ID 的な役割を果たすため、重複があるとエラーになる。AngularJS の 日本語リファレンス にはこう書かれている。

トラッキング関数が指定されなければ、ng-repeatはコレクション内で識別されてている要素を、結び付ける対象とします。トラッキング関数が同一のキーから複数の結果を得るとエラーになります。 (これは、同じDOM要素に2つの異なるオブジェクトをマッピングする事が出来ないことを意味します。)

つまり、以下のようなケースは Duplicate Key in Repeater エラーとなる。

<ul>
    <li ng-repeat="user in ['John', 'Paul', 'George', 'Ringo', 'John']">{{ user }}</li>
</ul>

このような単純な一次配列(でいいのかな)以外でも、たとえばコレクション内の各オブジェクトのキーがユニークになっていないときも、同様のエラーとなる。引用文では「同一のキーから複数の結果を得るとエラー」と書かれていてややこしいが、要はコレクション内に同一のキーを持ったオブジェクトが存在してはいけない、ということだ。

コレクション内の各要素をユニークにできない(もしくは運用上、重複する可能性がゼロではない)場合、トラッキング式を指定することで解決できる。もちろん、トラッキング式で指定するキーもユニークになる必要がある。上記のような単純な配列であれば、$index を使うのがもっとも簡単な解決方法になる。

<ul>
    <li ng-repeat="user in ['John', 'Paul', 'George', 'Ringo', 'John'] track by $index">{{ user }}</li>
</ul>