AngularJSでng-repeat時の生成内容を分岐させたい
Posted: Updated:
つまり
var items = [
{type : 'A'},
{type : 'B'},
{type : 'A'},
{type : 'A'},
{type : 'A'},
{type : 'B'},
{type : 'B'}
];
を ng-repeat 越しに
<ul>
<li ng-repeat="item in items">Aな感じの内容物</li>
<li ng-repeat="item in items">Bな感じの内容物</li>
<li ng-repeat="item in items">Aな感じの内容物</li>
<li ng-repeat="item in items">Aな感じの内容物</li>
<li ng-repeat="item in items">Aな感じの内容物</li>
<li ng-repeat="item in items">Bな感じの内容物</li>
<li ng-repeat="item in items">Bな感じの内容物</li>
</ul>
と出力したい。また、アイテムのタイプごとに振る舞いが異なるのでscope内に生やす実装内容も変えたい。
1stアタック
ng-include を使ってみた
たしかにテンプレートは変えられるが、実装が切り離せない。link 内で type みて、scopeの実装内容を判別する、とかそういう感じになりそう。
ていうか、件数増えるとなんか重い
少ない件数だとあまり気にならなかったのだが20件くらいに増やして、アイテムをソートしたり、追加したりのときにラグを感じる。なんで ng-repeat にこだわるかといえば、単純に angular-ui/ui-sortable を使ってしまいたかったからだ。
Watch Expressionsが、なかなか激しい様相を呈している。ng-include でHTMLを取り込んで出力する前に、parseAsTrustedな処理をしてるようだが、結構なウェイトを占めている。(件数が増えるとモリモリ昂ぶってくる)
2ndアタック
とかやってたら、$compile という記述を覚えたのでそっちで試してみた。
<type-of> ディレクティブを、ふつうに生成していって
app.directive('typeOf', ['$compile', function($compile) {
return {
restrict: 'E',
link: function(scope, element, attrs) {
var tagName = 'type-' + scope.item.type;
element.append($compile('<' + tagName + '>' + tagName + '>')(scope))
}
}
}]);
app..directive('typeA', function() {
return {
restrict: 'E',
templateUrl: 'A.html',
link: angular.noop
};
});
app.directive('typeB', function() {
return {
restrict: 'E',
templateUrl: 'B.html',
link: angular.noop
};
});
<type-of> ディレクティブの中でtypeに応じて、動的に生成すべきディレクティブを判別している。ディレクティブ的にまったく別なので、実装も心置きなく分離することができている。
サンプルコードでは省略しているが、<type-of> が isolate scopeであり、<type-A> とか <type-B> はスコープをそのまま継承する。( scope: false )
これならどうよ
ng-include による頻繁に評価されるインラインExpression + trustedAsHtml のコンボを抜けたことで、大分改善した。
クリティカルなパフォーマンス低下の因子は取り除けたと思われる。よかったよかった。
完全版サンプル (gist)
以上
説明の簡潔さから、AngularJSに対するわたしの愛を察して欲しい。深いよ。