AngularJS accessing DOM elements inside directive template

AngularjsAngularjs Directive

Angularjs Problem Overview


Is there a more "angular" way of selecting DOM elements inside a directive template? For example, say you have this directive:

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

I used the jQuery style selector to get a hold of the DOM <ul> element rendered in my template. Is there a better way to do this?

Angularjs Solutions


Solution 1 - Angularjs

I don't think there is a more "angular way" to select an element. See, for instance, the way they are achieving this goal in the last example of this old documentation page:

{
     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]),
        // ...
    }
}

Solution 2 - Angularjs

You could write a directive for this, which simply assigns the (jqLite) element to the scope using an attribute-given name.

Here is the directive:

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

Usage:

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

Some remarks:

  • Due to the compile and link order for nested directives you can only access scope.list from myDirectives postLink-Function, which you are very likely using anyway
  • ngScopeElement uses a preLink-function, so that directives nested within the element having ng-scope-element can already access scope.list
  • not sure how this behaves performance-wise

Solution 3 - Angularjs

This answer comes a little bit late, but I just was in a similar need.

Observing the comments written by @ganaraj in the question, One use case I was in the need of is, passing a classname via a directive attribute to be added to a ng-repeat li tag in the template.

For example, use the directive like this:

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

And get the following html:

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

The solution found here applied with templateUrl, would be:

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

Just tried it successfully with AngularJS 1.4.9.

Hope it helps.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDustinView Question on Stackoverflow
Solution 1 - AngularjsBlackholeView Answer on Stackoverflow
Solution 2 - AngularjsCodeSaladView Answer on Stackoverflow
Solution 3 - AngularjsGerardo CamachoView Answer on Stackoverflow