没有手表的角度一次性绑定

时间:2017-10-26 06:51:55

标签: javascript angularjs

我在Angular的一次性绑定方面遇到了麻烦。

假设我想使用带有一次时间绑定的ngIf,如下所示:

<div ng-if="::showImage">
    <img src="somesource" img-preloader/>
</div>

在这种情况下,angular会为if中的表达式创建一个监视。 一旦将其解析为未定义的值,手表就会被移除。

如果它被解析为真值,则将后代html树添加到DOM并随后呈现。

现在这一切都很棒但是我真的想避开最初的手表,只是解析表达式,如果它未定义 - 只有设置一个手表。原因在于我的情况相当复杂,但基本上我有一些暂时禁用不需要的手表的机制......

所以我一直在寻找内置角度的一次性绑定的替代品,并遇到了angular-once

Angular-once以不同的方式实现一次性绑定,它只在表达式被解析为未定义时设置临时监视,因此如果它在初始尝试中解析,则不会创建监视。听起来不错。

所以我可以这样做:

<div once-if="showImage">
    <img src="somesource" img-preloader/>
</div>

但是,这就是问题 - 显然,默认情况下首先呈现后代HTML树,然后如果解析为false,则从DOM中删除后代节点。

以下是执行此操作的代码段:

{
  name: 'onceIf',
  priority: 600,
  binding: function (element, value) {
    if (!value) {
      element.remove();
    }
  }
},

这对我来说是不好的行为,因为创建后代树是不可行的并导致其他问题,例如 - 在上面的示例中,将下载img。

所以我正在寻找一种在ngIf等指令中进行一次性绑定的方法,如果表达式成功解析并且不预先渲染后代树,则无需设置监视。

1 个答案:

答案 0 :(得分:-1)

我试图避免这种情况,但是现在我最终实现了基于Angular标准指令的自定义指令,但具有必要的附加功能。

ngIf派生指令:

app.directive('watchlessIf', ['$animate', '$compile', '$parse', function($animate, $compile, $parse) {
    return {
        multiElement: true,
        transclude: 'element',
        priority: 600,
        terminal: true,
        restrict: 'A',
        $$tlb: true,
        link: function($scope, $element, $attr, ctrl, $transclude) {
            function valueChangedAction(value) {
                if (value) {
                    if (!childScope) {
                        $transclude(function(clone, newScope) {
                            childScope = newScope;
                            clone[clone.length++] = $compile.$$createComment('end watchlessIf', $attr.watchlessIf);
                            block = {
                                clone: clone
                            };
                            $animate.enter(clone, $element.parent(), $element);
                        });
                    }
                } else {
                    if (previousElements) {
                        previousElements.remove();
                        previousElements = null;
                    }
                    if (childScope) {
                        childScope.$destroy();
                        childScope = null;
                    }
                    if (block) {
                        previousElements = getBlockNodes(block.clone);
                        $animate.leave(previousElements).then(function() {
                            previousElements = null;
                        });
                        block = null;
                    }
                }
            }

            var block, childScope, previousElements;
            if ($attr.watchlessIf.startsWith("::")) {
                var parsedExpression = $parse($attr.watchlessIf)($scope);
                if (parsedExpression != null) {
                    valueChangedAction(parsedExpression);
                    return;
                }
            }

            $scope.$watch($attr.watchlessIf, valueChangedAction);
        }
    };
}]);

ngBind派生指令:

app.directive('watchlessBind', ['$compile', '$parse', function($compile, $parse) {
    return {
        restrict: 'AC',
        compile: function watchlessBindCompile(templateElement) {
            $compile.$$addBindingClass(templateElement);
            return function watchlessBindLink(scope, element, attr) {
                function valueChangedAction(value) {
                    element.textContent = (typeof value == "undefined") ? '' : value;
                }

                $compile.$$addBindingInfo(element, attr.watchlessBind);
                element = element[0];
                if (attr.watchlessBind.startsWith("::")) {
                    var parsedExpression = $parse(attr.watchlessBind)(scope);
                    if (parsedExpression != null) {
                        valueChangedAction(parsedExpression);
                        return;
                    }
                }

                scope.$watch(attr.watchlessBind, valueChangedAction);
            };
        }
    };
}]);

注意:

  • 不幸的是,通过这种方法,我必须为其他Angular指令实现类似的指令,以及我希望支持可能无需监视的一次性绑定。

  • 我在指令中使用私有角度内容,比如$$ tlb选项,虽然我真的不应该......