AngularJSでng-repeat時の生成内容を分岐させたい

つまり

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 を使ってみた

<ul ui-sortable="sortableOptions" ng-model="items" id="list">
  <li ng-repeat="item in items">
    <p ng-include="item.type + '.html'"></p>
  </li>
</ul>

たしかにテンプレートは変えられるが、実装が切り離せない。link 内で type みて、scopeの実装内容を判別する、とかそういう感じになりそう。

ていうか、件数増えるとなんか重い

少ない件数だとあまり気にならなかったのだが20件くらいに増やして、アイテムをソートしたり、追加したりのときにラグを感じる。なんで ng-repeat にこだわるかといえば、単純に angular-ui/ui-sortable を使ってしまいたかったからだ。


sceParseAsTrustedさん....


Watch Expressionsが、なかなか激しい様相を呈している。ng-include でHTMLを取り込んで出力する前に、parseAsTrustedな処理をしてるようだが、結構なウェイトを占めている。(件数が増えるとモリモリ昂ぶってくる)

2ndアタック

とかやってたら、$compile という記述を覚えたのでそっちで試してみた。

<ul ui-sortable="sortableOptions" ng-model="items" id="list">
  <li ng-repeat="item in items">
    <type-of></type-of>
  </li>
</ul>

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