[英]AngularJS ngIf prevents finding element inside directive
我有一个包含ngIf
的AngularJS指令,我想在指令链接函数中修改ngIf
中的一些DOM。 不幸的是,似乎ngIf
阻止我在链接函数中查找其中的DOM元素。
以下是该指令的代码:
directive('column', function () {
return {
templateUrl: 'views/column.html',
restrict: 'E',
scope: {
column: '='
},
controller: ['$scope', function ($scope) {
$scope.editing = true;
$scope.toggleEditing = function () {
$scope.editing = !$scope.editing;
};
}],
link: function postLink(scope, element) {
var select = element.find('select');
console.log(select); // See if it can find the select element
// var types = scope.column.types();
// add types as options to the select element
}
};
});
这是指令的简化html:
<div class="column">
<div>{{ column.title }}</div>
<form name="columnForm" role="form" ng-if="editing">
<select></select>
</form>
</div>
这是jsFiddle示例http://jsfiddle.net/dedalusj/Y49Xx/1/的链接
link函数中的element.find
调用返回一个空数组,但是ngIf
从表单中删除ngIf
,它就会返回正确的select DOM元素。 我觉得我这样做的方式不对。
UPDATE
谢谢你的答案,但我找到了另一种解决方案。 我只是创建了另一个封装表单的指令,使用ng-if="editing"
将其添加到column
指令模板中。
form指令没有自己的作用域,所以它有效地在column
指令作用域内运行,并且总是访问select
元素,因为它在DOM树中。 我支付额外指令的费用,但我不必使用$timeout
hack。 我创建了一个新的jsFiddle来说明解决方案http://jsfiddle.net/dedalusj/nx3vX/1/
感谢@Michael,但我不能简单地使用ng-option
因为types
数组来自XML文件,其元素是其他angular.element对象,无法使用ng-option
轻松插入。
ngIf
指令使用Angular的ngIf
功能。 在编译/链接循环期间发生的事情是:
ngIf
的内容将从DOM中删除 ngIf
的链接函数在使用它的指令的link函数之前运行。 当ngIf
的链接函数运行时,它使用$scope.$watch()
来监视ng-if
属性的值。 ngIf
的内容不是DOM的一部分 ngIf
将调用$transclude
ngIf
函数,如果ng-if
属性值为真,则将ngIf
的内容插入到DOM中。 $timeout
调用或$scope.$evalAsync
使用$scope.$evalAsync
您在指令的链接函数中注册的$scope.$evalAsync
将运行。 因此,如果您想访问ngIf
内容中的元素,则代码需要在上面的步骤4 之后运行。 这意味着在指令的链接函数中使用$scope.$watch
, $timeout
或$scope.$evalAsync
注册的任何函数都可以使用。 对于一次性设置代码,我可能会选择$scope.$evalAsync
:
angular.directive('yourDirective', function () {
return {
...
link: function(scope, elem) {
scope.$evalAsync(function () {
// code that runs after conditional content
// with ng-if has been added to DOM, if the ng-if
// is enabled
});
}
};
});
正如@moderndegree所说, ngIf
从DOM中删除它所应用的元素,因此当它不存在时你将无法找到它。 但是,您可以通过以下方式编写指令:
controller: function ($scope, $element, $timeout) {
$scope.toggleEditing = function () {
$scope.editing = !$scope.editing;
$timeout(function() {
var select = $element.find('select');
select.append('<option>Value 1</option>')
.append('<option>Value 2</option>')
.append('<option>Value 3</option>');
});
};
}
在这里更新了jsFiddle。
这里的技巧是通过使用带有0间隔的$timeout
来延迟find()
调用,以便等待Angular更新DOM。
UPDATE
在对代码进行更多考虑之后,我意识到也许你可以让Angular为你做出艰苦的工作:
使用Javascript
directive('column', function () {
return {
templateUrl: 'views/column.html',
restrict: 'E',
scope: {
column: '='
},
controller: ['$scope', function ($scope) {
$scope.editing = true;
$scope.toggleEditing = function () {
$scope.editing = !$scope.editing;
};
}],
};
});
HTML
<div class="column">
<div>{{ column.title }}</div>
<form name="columnForm" role="form" ng-if="editing">
<select ng-model="type" ng-options="type for type in column.types"></select>
</form>
</div>
现在您不必担心在正确的时间找到select
元素并填充它。 Angular为您做了所有这些。 :)
您可以将链接函数中的代码放在$ timeout内。
$timeout(function(){
var select = element.find('select');
console.log(select);
});
不要忘记在你的指令中注入$ timeout
directive('column', function ($timeout) {
我遇到了同样的问题而且我能够使用ng-show解决它,这可以防止这个问题,因为ngIf删除了它应用于DOM的元素,所以当它不存在时你将无法找到它。
所以在你的情况下:
<div class="column">
<div>{{ column.title }}</div>
<form name="columnForm" role="form" ng-show="editing">
<select></select>
</form>
会好起来的。
干杯。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.