🅰️
ng-repeatでのフィルタをフックする
(2014/10/25 追記)この記事は半年以上前に執筆したものです。
--
とくに何もせずng-repeat
に Filter を指定すれば検索ができてしまうのが AngularJS の魅力ですが、この処理の前後に独自の処理を挟みたいときはどうするか考えてみました。
Filter 処理をフックする方法
Controller の実装については省略しています。
var myApp = angular.module("myApp", ["ngRoute"]);
myApp.filter("myFilter", function ($filter) {
return function (items, input) {
/* Filter前の何らかの処理 */
var result = $filter("filter")(items, input); // ここでネイティブのfilterを呼ぶ
/* Filter後の何らかの処理 */
return result;
};
});
index.html
<input ng-model="search" />
<table>
<tr ng-repeat="e in entities | myFilter:search">
<td>{{e.name}}</td>
</tr>
</table>
これで OK。var result = $filter('filter')(items, input);
がポイントなんですね。この前後でいろいろできます。データが多い時に逐一やるとかなり重いので対策は必要になってきます。<input>
にng-change
属性を与えて debounce するのも手です。
また、この引数の取り方を覚えておけば他の何らかのフィルターを自作することも可能です。
応用
DOM 反映後に処理をする場合
Filter のreturn result;
行にて戻ったオブジェクトが検索結果として DOM に反映されるわけですが、このフック処理は「反映前」に行われます。反映後に更に処理を行いたい場合は$scope.$watch()
を使うとよさそうです。jQuery やgetElementById()
辺りはフック処理に書いても動かないので注意。
表示上の順序と$index が一致しない
これは画面上ではフィルタ済み、保持しているオブジェクトはフィルタ前と異なるからです。フック処理でフィルタ後のオブジェクトを保持すれば、その配列インデックスと見た目の上での順序が一致します。nextSibling
の使い勝手が微妙な中、何かと便利。
Discussion