title: AngularJS: What's the best practice to add ngIf to a directive programmatically?
body: <p>I want to create a directive that checks if an element should be present in the dom based on a value coming from a service (e.g. check for a user role).</p>
  
  <p>The corresponding directive looks like this:</p>
  
  <pre><code>angular.module('app', []).directive('addCondition', function($rootScope) {
      return {
          restrict: 'A',
          compile: function (element, attr) {
            var ngIf = attr.ngIf,
                value = $rootScope.$eval(attr.addCondition);
  
            /**
             * Make sure to combine with existing ngIf!
             * I want to modify the expression to be evalued by ngIf here based on a role 
             * check for example
             */
            if (ngIf) {
              value += ' &amp;&amp; ' + ngIf;
            }
  
            attr.$set('ng-if', value);
          }
      };
  });
  </code></pre>
  
  <p>At the end the element has the ng-if attribute attached but somehow it doesn't apply to the element and it is still existing in the dom. So this is obviously a wrong approach. </p>
  
  <p>This fiddle shows the problem: <a href="http://jsfiddle.net/L37tZ/2/">http://jsfiddle.net/L37tZ/2/</a></p>
  
  <p>Who can explain why this happens? Is there any other way a similar behaviour could be achieved? Existing ngIfs should be considered.</p>
  
  <h1>SOLUTION:</h1>
  
  <p>Usage: <code>&lt;div rln-require-roles="['ADMIN', 'USER']"&gt;I'm hidden when theses role requirements are not satifisfied!&lt;/div&gt;</code></p>
  
  <pre><code>.directive('rlnRequireRoles', function ($animate, Session) {
  
    return {
      transclude: 'element',
      priority: 600,
      terminal: true,
      restrict: 'A',
      link: function ($scope, $element, $attr, ctrl, $transclude) {
        var block, childScope, roles;
  
        $attr.$observe('rlnRequireRoles', function (value) {
          roles = $scope.$eval(value);
          if (Session.hasRoles(roles)) {
            if (!childScope) {
              childScope = $scope.$new();
              $transclude(childScope, function (clone) {
                block = {
                  startNode: clone[0],
                  endNode: clone[clone.length++] = document.createComment(' end rlnRequireRoles: ' + $attr.rlnRequireRoles + ' ')
                };
                $animate.enter(clone, $element.parent(), $element);
              });
            }
          } else {
  
            if (childScope) {
              childScope.$destroy();
              childScope = null;
            }
  
            if (block) {
              $animate.leave(getBlockElements(block));
              block = null;
            }
          }
        });
      }
    };
  });
  </code></pre>
  
  <p>It is very important to add the priority in the directive, otherwise other directives attached to that element are not evaluated!</p>