AngularJS - How to use ng-if without HTML element

There's a currently-undocumented pair of directives, ng-if-start and ng-if-end, that you can use for this. They behave analogously to the documented ng-repeat-start and ng-repeat-end directives, and you can see the unit tests for them if you like.

For example, given the following code:

<ul>
  <li ng-if-start="true">a</li>
  <li>b</li>
  <li>c</li>
  <li ng-if-end>d</li>
  <li ng-if-start="false">1</li>
  <li>2</li>
  <li>3</li>
  <li ng-if-end>4</li>
</ul>

the first four lis will be shown and the final four lis will be hidden.

Here's a live example on CodePen: http://codepen.io/anon/pen/PqEJYV

There are also ng-show-start and ng-show-end directives that work exactly the way you would expect them to.


If you are happy to create a custom directive, you can apply the ng-if to the children programmatically and flatten the DOM in the process:

Directive Code:

.directive('ngBatchIf', function() {
    return {
        scope: {},
        compile: function (elm, attrs) {
            // After flattening, Angular will still have the first element
            // bound to the old scope, so we create a temporary marker 
            // to store it
            elm.prepend('<div style="display: none"></div>');

            // Flatten (unwrap) the parent
            var children = elm.children();
            elm.replaceWith(children);

            // Add the ng-if to the children
            children.attr('ng-if', attrs.ngBatchIf);

            return {
                post: function postLink(scope, elm) {
                    // Now remove the temporary marker
                    elm.remove();
                }
            }
        }
    }
})

Angular Code:

<div id="div1" ng-batch-if="checked">
    <div id="div2">ABC</div>
    <div id="div3">KLM</div>
    <div id="div4">PQR</div>
</div>

Rendered HTML:

<div id="div2" ng-if="checked">ABC</div>
<div id="div3" ng-if="checked">KLM</div>
<div id="div4" ng-if="checked">PQR</div>

Fiddle: http://jsfiddle.net/o166xg0s/4/