设置ngIf的Angular指令

时间:2017-04-24 08:52:02

标签: angularjs typescript angular-ng-if

我的应用程序中有一些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吗?否则,是否有其他方法可以确保在ng-show条件至少为真之前元素不会被添加到DOM中?

谢谢!

1 个答案:

答案 0 :(得分:1)

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

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指令,并在链接阶段手动编译它。

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

DEMO on PLNKR