Javascript AngularJS ngIf阻止在指令内查找元素

Javascript AngularJS ngIf阻止在指令内查找元素,javascript,angularjs,Javascript,Angularjs,我有一个包含ngIf的AngularJS指令,我想在指令链接函数中修改ngIf中的一些DOM。不幸的是,ngIf似乎阻止我在link函数中查找其中的DOM元素 以下是该指令的代码: directive('column', function () { return { templateUrl: 'views/column.html', restrict: 'E', scope: { column: '=' }, c

我有一个包含
ngIf
的AngularJS指令,我想在指令链接函数中修改
ngIf
中的一些DOM。不幸的是,
ngIf
似乎阻止我在link函数中查找其中的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
      }
    };
  });
<div class="column">
    <div>{{ column.title }}</div>
    <form name="columnForm" role="form" ng-if="editing">
        <select></select>
    </form>
</div>
以下是该指令的简化html:

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
      }
    };
  });
<div class="column">
    <div>{{ column.title }}</div>
    <form name="columnForm" role="form" ng-if="editing">
        <select></select>
    </form>
</div>

{{column.title}}
下面是指向JSFIDLE示例的链接

link函数中的
元素.find
调用返回一个空数组,但只要我从表单中删除
ngIf
,它就会返回正确的select DOM元素。我觉得我这样做是不对的

更新

谢谢你的回答,但我找到了另一个解决办法。我只是创建了另一个封装表单的指令,并使用
ng if=“editing”
将其添加到
指令模板中

表单指令没有自己的作用域,因此它有效地在
指令作用域之外运行,并且始终可以访问
select
元素,因为它位于其DOM树中。我支付额外指令的费用,但我不必使用
$timeout
hack。我创建了一个新的JSFIDLE来说明解决方案


谢谢@Michael,但我不能简单地使用
ng选项
,因为
类型
数组来自一个XML文件,它的元素是其他angular.element对象,使用
ng选项
很难插入

正如@modendegree所说,
ngIf
从DOM中删除应用它的元素,因此当它不在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>');
    });            
  };
}
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>

{{column.title}}


现在,您不必担心在正确的时间找到
select
元素并填充它。Angular为您完成了所有这一切。:)

您可以将链接函数中的代码放入$timeout中

$timeout(function(){
     var select = element.find('select');
     console.log(select);
});
不要忘记在指令中注入$timeout

directive('column', function ($timeout) {

ngIf
指令通过使用Angular的转换功能工作。编译/链接周期中发生的情况是:

  • 编译时,
    ngIf
    中的内容将从DOM中删除
  • Angular运行链接函数。
    ngIf
    的链接功能在 使用它的指令的链接函数。当
    ngIf
    的链接功能 运行时,它使用
    $scope.$watch()
    来监视
    ng的值(如果
    属性
  • 您的指令的link函数运行,此时
    ngIf
    的内容不是DOM的一部分
  • 调用步骤(2)中设置的手表,如果
    ng if
    属性值为truthy,则
    ngIf
    将调用
    $transclude
    函数将
    ngIf
    的内容插入DOM
  • 在指令的链接函数中注册的任何监视函数、
    $timeout
    调用或使用
    $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
          });
        }
      };
    });
    

    我曾经遇到过同样的问题,我能够使用ng show解决这个问题,这可以防止出现这个问题,因为ngIf删除了它应用于DOM的元素,所以当它不存在时,您将无法找到它

    因此,在你的情况下:

    <div class="column">
    <div>{{ column.title }}</div>
    <form name="columnForm" role="form" ng-show="editing">
        <select></select>
    </form>
    
    
    {{column.title}}
    


    干杯。

    ngIf阻止将元素添加到DOM中。使用ngShow您可能会更幸运。是的,这是事实,但表单可以包含多个其他指令,并且它所属的指令在文档中多次出现,因此最好不要将其全部包含在DOM中。我希望有一种方法可以做到这一点。下面是一个Plunker,它通过基于Angular 1.4.x中的源代码的自定义版本的
    ngIf
    演示了这一点:使用
    ng时,show
    元素将加载到DOM中,在大多数情况下它是不需要的