Angular 设置 ngIf 的指令

Angular directive that sets ngIf

我的应用程序中有一些 DOM 元素加载起来相当昂贵,因此我一直在使用以下模式来确保在需要时才加载它们:

<div ng-if="someCondition || everShown" ng-show="someCondition">

本质上,这确保元素仅在 someCondition 为真时才添加到 DOM,然后它会保留在那里。但是,那里有相当多的重复逻辑,因此我想将逻辑提取到一个指令中。

这是我的尝试:

export function IfEverShown($parse: angular.IParseService): angular.IDirective {    
    return {
        restrict: "A",
        compile: function(element: angular.IAugmentedJQuery,
                          attributes: angular.IAttributes) {
            if (!attributes["ngShow"]) {
                return;
            }
            element.attr("ng-if", "everShown");

            return {
                pre: function(scope: angular.IScope) {
                    scope["everShown"] = false;
                    attributes.$observe('ngShow', function (expr) {
                        scope.$watch(function () {
                            return $parse(<any> expr)(scope);
                        }, function (value) {
                            if (value) {
                                scope["everShown"] = true;
                            }
                        });
                    });
                }
            };
        }
    };
}

用法将是:

<div ng-show="someCondition" if-ever-shown>

然而,即使 DOM 中的 ng-if 值按预期变化,Angular 也只是忽略了它上面的变化:如果没有之前的 ng-if,元素总是出现在 DOM 中,如果有以前的值,即使我更改它也总是观察到它。

我怎样才能在这里获得所需的行为?我可以从指令修改 ngIf 吗?否则,是否有其他方法可以确保元素不会添加到 DOM 直到 ng-show 条件至少一次为真?

谢谢!

$compile service 不会自动编译在编译阶段添加到元素的指令。任何新添加的指令都需要在 link 阶段手动编译:

app.directive("myIf", function($compile) {
  return {
    priority: 1000,
    terminal: true,
    compile: function(tElem, tAttrs) {
      tAttrs.$set("ngIf", tAttrs.myIf);
      tAttrs.$set("myIf", null);
      return postLink;
    }
  }
  function postLink(scope, elem, attrs) {
    $compile(elem)(scope);
  }
});

以上示例演示了一个名为 my-if 的自定义指令。它在编译阶段添加了一个 ng-if 指令,并在 link 阶段手动编译它。

请注意,它是作为高优先级 "terminal" 指令实现的,并且它删除了 my-if 属性,因此指令只编译一次。

DEMO on PLNKR.