我在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等指令中进行一次性绑定的方法,如果表达式成功解析并且不预先渲染后代树,则无需设置监视。
答案 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选项,虽然我真的不应该......