Угловой JS доступ к элементам DOM внутри шаблона директивы

Есть ли способ "angular" выбрать элементы DOM внутри шаблона директивы? Например, скажем, у вас есть эта директива:

app.directive("myDirective", function() {
    return {
        template: '<div><ul><li ng-repeat="item in items"></ul></div>',
        link: function(scope, element, attrs) {
            var list = element.find("ul");
        }
    }
});

Я использовал селектор стиля jQuery, чтобы получить элемент DOM <ul>, выделенный в моем шаблоне. Есть ли лучший способ сделать это?

Ответ 1

Вы можете написать для этого директиву, которая просто присваивает элемент (jqLite) области видимости с именем, заданным атрибутом.

Вот директива:

app.directive("ngScopeElement", function () {
  var directiveDefinitionObject = {

    restrict: "A",

    compile: function compile(tElement, tAttrs, transclude) {
      return {
          pre: function preLink(scope, iElement, iAttrs, controller) {
            scope[iAttrs.ngScopeElement] = iElement;
          }
        };
    }
  };

  return directiveDefinitionObject;
});

Использование:

app.directive("myDirective", function() {
    return {
        template: '<div><ul ng-scope-element="list"><li ng-repeat="item in items"></ul></div>',
        link: function(scope, element, attrs) {
            scope.list[0] // scope.list is the jqlite element, 
                          // scope.list[0] is the native dom element
        }
    }
});

Некоторые замечания:

  • Благодаря компиляции и порядку ссылок для вложенных директив вы можете получить доступ только к scope.list из myDirective postLink-Function, которые вы очень вероятно, используя в любом случае
  • ngScopeElement использует функцию preLink, так что директивы, вложенные в элемент, имеющий ng-scope-element, уже могут получить доступ к scope.list
  • не уверен, как это ведет себя с точки зрения производительности

Ответ 2

Я не думаю, что для выбора элемента существует более "angular способ". См., Например, то, как они достигают этой цели в последнем примере этой старой страницы документации:

{
     template: '<div>' +
    '<div class="title">{{title}}</div>' +
    '<div class="body" ng-transclude></div>' +
    '</div>',

    link: function(scope, element, attrs) {
        // Title element
        var title = angular.element(element.children()[0]),
        // ...
    }
}

Ответ 3

Этот ответ приходит немного позже, но я просто нуждался.

Наблюдение за комментариями, написанными @ganaraj в вопросе, Один случай использования, в котором я нуждался, - передать имя класса через атрибут директивы, который будет добавлен в тег ng-repeat li в шаблоне.

Например, используйте следующую директиву:

<my-directive class2add="special-class" />

И получите следующий html:

<div>
    <ul>
       <li class="special-class">Item 1</li>
       <li class="special-class">Item 2</li>
    </ul>
</div>

Решение найдено здесь, применяемое с templateUrl, будет:

app.directive("myDirective", function() {
    return {
        template: function(element, attrs){
            return '<div><ul><li ng-repeat="item in items" class="'+attrs.class2add+'"></ul></div>';
        },
        link: function(scope, element, attrs) {
            var list = element.find("ul");
        }
    }
});

Просто попробовал это с помощью AngularJS 1.4.9.

Надеюсь, что это поможет.