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に対するわたしの愛を察して欲しい。深いよ。