【问题标题】:How to select dynamically generated elements from inside an AngularJS directive?如何从 AngularJS 指令中选择动态生成的元素?
【发布时间】:2014-12-28 17:52:10
【问题描述】:

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

虽然这可行,但它不是一个理想的解决方案,而且看起来肯定不是最佳实践。一方面,您希望尽可能缩短超时时间,但另一方面,您希望确保 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   

    };
});

【问题讨论】:

  • 我认为另一个问题可能是为什么选择这些元素?以更角度(i)的方式进行操作会将这些类绑定到视图模型,这将处理整个异步问题。
  • 正如@Tomer 所说,这与 Angular 的工作方式完全相反...为什么不将所有指令内容放在指令模板中,从而使其始终可用?
  • 总而言之,看看stackoverflow.com/questions/17643681/…,这似乎是一种角度的方式,但这stackoverflow.com/questions/13471129/…可能是一个更好的方法
  • @Shomz:我想保持指令的通用性和可重用性,而不是绑定到任何特定的视图。

标签: javascript html angularjs angularjs-directive angularjs-ng-repeat


【解决方案1】:

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

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();
                }
            }
        };
    })

顺便说一句 不要触摸控制器中的 dom :)

【讨论】:

    猜你喜欢
    • 2015-04-12
    • 2013-10-07
    • 1970-01-01
    • 2013-07-24
    • 1970-01-01
    • 2014-10-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多