我认为这很简单,但它似乎不是!
我尝试创建一个通用属性指令,该指令将调用我的某个服务中的方法,并且如果服务方法返回,则有条件地导致放置它的元素不会添加到DOM中假。基本上,ng-if,但是如果内部调用服务方法并对其采取行动
我有一个包含属性指令的元素:例如
<p ng-if="visible" my-directive>Hi</p>
我在myDirective指令中将visible
设置为true。我{em>期待 <p>
元素在visible
假的时候从DOM中删除,并在它真实的时候添加到DOM中。相反,ng-if似乎永远不会发现在指令的链接函数中已经将visible设置为true,因此<p>
元素永远不会显示。
我不能100%确定它会起作用,因为指令正在移除它所存在的元素,那里有一个捕获22。
我在这方面花了太长时间,到目前为止尝试过(不成功):
attr.ngIf = true;
element.attr('ng-if', true);
<p>
中的ng-if更改为ng-show,从而不删除元素(我真的想要这样做)我想知道它是否像范围一样简单?由于ng-if绑定到<p>
元素的属性,因此在指令范围内设置visible
会将其设置在同一范围内吗?
另一方面,我可能会过度简化,我有一种讨厌的感觉,我可能不得不考虑指令编译和转换以获得解决方案。
有没有人对我可能出错的地方有任何感觉?
答案 0 :(得分:1)
tldr:显然你希望你的指令是自包含的,它应该能够删除并将自己添加到DOM中。这是可能的,并通过DOM的隔离范围或手动操作最有意义(见下文)。
常规的
当<p ng-if="visible" my-directive>Hi</p>
角度查找当前范围的visible
时,该范围是指令的父范围。当定义visible
时,该指令被插入到DOM中,例如取自你的掠夺者
<body ng-controller="MainCtrl">
<p my-directive="showMe" ng-if="visible">I should be shown</p>
</body>`<br>
app.controller('MainCtrl', function($scope) {
$scope.visible = 3;
});
会显示指令。当您在指令上定义隔离范围时
app.directive('myDirective', function() {
return {
restrict: 'A',
scope: {
myDirective: '='
},
link: function(scope, element, attr, ctrl) {
scope.visible = (scope.myDirective == 'showMe') ? true : false;
}
}
});
指令中的 scope.visible
不会影响visible
考虑的ngIf
。
儿童范围
您可以定义子范围以访问父范围。如果你这样做,你实际上可以影响正确的visible
属性,但你必须将它放在一个对象上,以便指令可以遵循范围原型链。
<body ng-controller="MainCtrl">
<p my-directive ng-if="visibleDirectives.directive1">I should be shown</p>
</body>
$timeout
用于演示目的。最初,ngIf
必须评估为true,否则根本不会创建指令。
app.controller('MainCtrl', function($scope) {
$scope.visibleDirectives = { directive1 : true };
});
app.directive('myDirective', function($timeout) {
return {
restrict: 'A',
scope : true,
link: function(scope, element, attr, ctrl) {
console.log(scope);
$timeout(function() {
scope.visibleDirectives.directive1 = !scope.visibleDirectives.directive1;
$timeout(function() {
scope.visibleDirectives.directive1 = !scope.visibleDirectives.directive1;
}, 2000);
}, 2000);
}
}
});
这样的指令必须知道预先定义它的可见性的属性(在这种情况下是scope.visibleDirectives.visible1
),这不是很实用,并且禁止了几个指令。
隔离范围
在您的示例中,您使用了隔离范围。这允许重用指令。为了使指令能够修改ngIf
的相应属性,您必须再次为其提供正确的引用。
<body ng-controller="MainCtrl">
<p my-directive="directive1" ng-if="directive1.visible">I should be shown</p>
</body>
同样,您必须在对象上提供属性,以便指令可以跟随对象引用来修改右visible
。
app.controller('MainCtrl', function($scope) {
$scope.directive1 = {
visible : true
};
});
app.directive('myDirective', function($timeout) {
return {
restrict: 'A',
scope : {
myDirective : '='
},
link: function(scope, element, attr, ctrl) {
$timeout(function() {
scope.myDirective.visible = !scope.myDirective.visible;
$timeout(function() {
scope.myDirective.visible = !scope.myDirective.visible;
}, 2000);
}, 2000);
}
}
});
在这些情况下,每次ngIf
计算结果为true时,都会重新创建指令。
手动操作DOM
<body ng-controller="MainCtrl">
<p my-directive>I should be shown</p>
</body>
在这种情况下,您不需要setTimeout
的角度版本,甚至可以使用setInterval
因为Interval只创建一次,但您必须清除它。
app.controller('MainCtrl', function($scope) { });
app.directive('myDirective', function() {
return {
restrict: 'A',
scope : { },
link: function(scope, element, attr, ctrl) {
var el = element[0];
var parent = el.parentNode;
var shouldBeShown = false;
var interval = setInterval(function() {
var children = parent.children;
var found = false;
for(var i = 0; i < children.length; i++) {
if(children[i] === el) {
found = true;
break;
}
}
if(shouldBeShown) {
if(!found)
parent.appendChild(el);
}
else {
if(found)
parent.removeChild(el);
}
shouldBeShown = !shouldBeShown;
}, 2000);
scope.$on('$destroy', function() {
clearInterval(interval);
});
}
};
});
答案 1 :(得分:0)
如果要删除元素,请使用ng-show =&#34; visible&#34;这将作为布尔值进行计算,并在元素计算结果为true时显示该元素。使用&#34;!可见&#34;如果你需要翻转它。
此外,但是将scope属性添加到您的指令中,您正在添加一个额外的作用域,考虑备用时间轴,即与页面关联的控制器作用域无法看到。这可以解释为什么ng-show之前可能不适合你。