2

在我的指令中,我需要选择某些DOM元素,其中一些是在ng-repeat循环中动态生成的。如果我以直截了当的方式来做,我只会得到静态元素。但是,如果我延迟选择,例如500毫秒,我将获得所有元素,这正是我想要的。如何从AngularJS指令中选择动态生成的元素?

虽然这有效,但它不是一个理想的解决方案,而且当然也不是最佳实践。一方面,您希望尽可能缩短超时时间,但另一方面,您希望在选择之前确保DOM已准备就绪。

当所有动态DOM准备就绪时,是否有事件触发?从AngularJS指令中选择动态生成的元素的推荐方法是什么?

例:

HTML:

<div data-my-directive> 
    <div class="modal-body">       
     <label data-localize>type:</label>&nbsp; 
     <select class="form-control" ng-model="assetFilter.appCode" ng-change="loadassets(assetFilter.appCode)" ng-options="type.code as type.name for type in types"></select> 

      <table class="table table-default" ng-show="hasLoaded"> 
       <tbody ng-repeat="asset in assets | filter:assetFilter | orderBy:'assetKey':false"> 
       <tr> 
        <td> 
         <div class="container-fluid"> 
          <div class="row vert-align"> 
           <div class="col-sm-4"> 
            {{asset.assetKey}} 
           </div> 
           <div class="col-sm-8" style="height:100%"> 
            <input ng-hide="asset.assetKey.length >= 80" type="text" class="form-control" ng-model="asset.assetValue" ng-change="asset.isModified=true"> 
            <textarea ng-show="asset.assetKey.length > 80" class="form-control" ng-model="asset.assetValue" ng-change="asset.isModified=true"></textarea> 
           </div> 
          </div> 
         </div> 
        </td> 
       </tr> 
      </tbody> 
     </table> 

    </div> 
    <div class="modal-footer"> 
     <button class="btn btn-primary" ng-click="save(saveassets, $event)" ng-disabled="!(assets | anyModified)" data-localize>Save</button> 
     <button class="btn btn-warning" ng-click="close($event)" data-localize>Close</button> 
    </div> 
</div> 

指令:

myApp.directive('myDirective', function ($timeout) { 
    return { 
     restrict: 'A', //attribute only 
     link: function (scope, elem, attr, ctrl) {  
      var context = elem[0]; 
      var availableFormElements = 'input:not([disabled]):not([class*=ng-hide]),' + 
       'select:not([disabled]):not([class*=ng-hide]), textarea:not([disabled]):not([class*=ng-hide]),' + 
       'button:not([disabled]):not([class*=ng-hide]),' + 
       '*[class*=btn]:not([disabled]):not([class*=ng-hide])'; 

      var allFormElements = context.querySelectorAll(availableFormElements); 
      // Will only get static elements, nothing from ng-repeat loop 

      $timeout(function() { 
       allFormElements = context.querySelectorAll(availableFormElements); 
       // Will include all elements, also from ng-repeat loop 
      }, 500);  

      // Code to manipulate selected form elements 

    }; 
}); 
+2

我想另一个问题可能是为什么选择这些元素?以更加有角度的方式做它会绑定这些类来查看将处理整个异步问题的模型。 – Tomer 2014-11-01 16:11:04

+0

正如@Tomer所说,这与Angular的工作方式完全相反......你为什么不把所有的指令内容都放在指令模板中,并且一直都可用? – Shomz 2014-11-01 18:01:50

+1

总而言之,它似乎角度的方式看看http://stackoverflow.com/questions/17643681/angularjs-linking-to-elements-in-a-directive-that-uses-ng-repeat但这个http: //sackoverflow.com/questions/13471129/angularjs-ng-repeat-finish-event可能是更好的方法 – Whisher 2014-11-01 18:33:37

回答

1

这是一个简单的例子,你如何可以工作了。 Imo该解决方案的唯一缺点是不能使用隔离范围。

HTML

<div data-ng-controller="MainController"> 
    <div outer-directive> 
     <ul> 
      <li ng-repeat="asset in assets" inner-directive> 
         {{asset}} 
         <input type="text" class="form-control"> 
      </li> 
     </ul> 
    </div> 
</div> 

JS

var app = angular.module('myApp', []); 

app.controller('MainController',function($scope) { 
    $scope.assets = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]; 
}); 

app.directive('outerDirective', function() { 
    return { 
    restrict: 'A', 
    controller: function($scope) { 

    } 
    }; 
}); 
app.directive('innerDirective', function() { 
    return { 
    restrict: 'A', 
    require: '^outerDirective', 
    link: function(scope, elem, attrs,ctrl) { 
     var context = elem[0]; 
     if (scope.$last){ 
      var availableFormElements = 'input,textarea'; 
      var allFormElements = context.querySelectorAll(availableFormElements); 
      console.log(allFormElements); 
     } 
    } 
    }; 
}); 

或更好

.directive('myParent', function ($timeout) { 
     return { 
      restrict: 'A', //attribute only 
      controller: function ($scope, $element) { 
       this.isDone = function(){ 
        var context = $element[0]; 
        var availableFormElements = 'input,textarea'; 
        var allFormElements = context.querySelectorAll(availableFormElements); 
        console.log(allFormElements); 
       } 
      } 
     }; 
    }) 
    .directive('myChild', function ($timeout) { 
     return { 
      require:'^myParent', 
      restrict: 'A', //attribute only 
      link: function (scope, elem, attr, ctrl) {  

       if (scope.$last){ 
        ctrl.isDone(); 
       } 
      } 
     }; 
    }) 

BTW 不要触摸控制器中的dom :)