title: AngularJS : ng-repeat vs $interpolate
body: <p>From what I have seen with Angular 2.0, I have a feeling I am going to be using Angular 1.x for a while.  It has all the building blocks that I think I need, the only downside is that it does have performance issue with dirty checking so I am trying to think about that more.  Now ng-repeat can be an issue because of the number of watchers it adds.</p>
  
  <p>So I have this part of a template (in jade):</p>
  
  <pre><code>li(ng-repeat='topMenuItem in sideMenu.topMenu', ng-class='{"is-active": topMenuItem.display === sideMenu.activeTopMenu}')
    a(href='{{ topMenuItem.href }}') {{ topMenuItem.display }}
      ul(ng-if='sideMenu.secondMenu.length &gt; 0 &amp;&amp; topMenuItem.display === sideMenu.activeTopMenu')
        li(ng-repeat='secondMenuItem in sideMenu.secondMenu', ng-class='{"is-active": secondMenuItem.display === sideMenu.activeSecondMenu}')
          a(href='{{ secondMenuItem.href }}') {{ secondMenuItem.display }}
  </code></pre>
  
  <p>When this displays 22 menu items the number of watchers is 90 (using <a href="http://blog.yodersolutions.com/angularjs-count-the-number-of-watchers-on-a-page/" rel="nofollow">this</a> bookmark snippet).</p>
  
  <p>I decided to play around with trying to use $interpolate to generate that menu.  I ended up with a directive with this for the compile function:</p>
  
  <pre><code>compile: function(element, attributes) {
    var topLevelExpression = $interpolate('&lt;li{{ cssClass }}&gt;&lt;a href="{{ topMenuItem.href }}"&gt;{{ topMenuItem.display }}&lt;/a&gt;{{ secondLevelMenuHtml }}&lt;/li&gt;');
    var secondLevelExpression = $interpolate('&lt;li{{ cssClass }}&gt;&lt;a href="{{ secondMenuItem.href }}"&gt;{{ secondMenuItem.display }}&lt;/a&gt;&lt;/li&gt;');
  
    var updateMenu = function() {
      var html = '';
  
      sideMenu.topMenu.forEach(function(topMenuItem) {
        var cssClass = topMenuItem.display === sideMenu.activeTopMenu ? ' class="is-active"': '';
        var secondLevelMenuHtml = '';
  
        if(sideMenu.secondMenu.length &gt; 0 &amp;&amp; topMenuItem.display === sideMenu.activeTopMenu) {
          secondLevelMenuHtml += '&lt;ul&gt;';
  
          sideMenu.secondMenu.forEach(function(secondMenuItem) {
  
            var cssClass = secondMenuItem.display === sideMenu.activeSecondMenu ? ' class="is-active"': '';
            secondLevelMenuHtml += secondLevelExpression({
              secondMenuItem: secondMenuItem,
              cssClass: cssClass,
            });
          });
  
          secondLevelMenuHtml += '&lt;/ul&gt;';
        }
  
        html += topLevelExpression({
          topMenuItem: topMenuItem,
          cssClass: cssClass,
          secondLevelMenuHtml: secondLevelMenuHtml
        });
      });
  
      element.find('.application-navigation').html(html);
    };
  
    return function($scope) {
      $scope.$watchCollection('sideMenu', function() {
        updateMenu();
      });
    }
  }
  </code></pre>
  
  <p>From my testing, this code functions exactly the same as the ng-repeat, the output look as it should.  This version only has 16 watchers and that number does not increase when more elements are shown where the ng-repeat does.</p>
  
  <p>Since this code is only doing the bare minimum that is needed for this piece of code to work, I imagine the javascript itself is just as efficient (if not more efficient) than the code that executes for ng-repeat.</p>
  
  <p>Is that assumption correct?</p>
  
  <p>Are there any issues with doing looping DOM generation in this way vs using ng-repeat?</p>