Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AngularJS - Find Element with attribute

Tags:

angularjs

I'm new to AngularJS. I've learned that I can find elements in the DOM using queries like the following:

var e = angular.element(document.querySelector('#id'));
var e = angular.element(elem.querySelector('.classname'));

This is useful for finding elements by ID, or by CSS class name. However, I need to be able to find an element using a different approach. I have an element that looks like the following:

<div my-directive class='myContainer'>...</div>

I can't query on 'myContainer' because of how much its reused. For that reason, I would like to find any element with the attribute 'my-directive'. How do I search the DOM and find any element that makes use of 'my-directive'?

like image 599
user3111277 Avatar asked Dec 27 '13 13:12

user3111277


3 Answers

Rather than querying the DOM for elements (which isn't very angular see "Thinking in AngularJS" if I have a jQuery background?) you should perform your DOM manipulation within your directive. The element is available to you in your link function.

So in your myDirective

return {
    link: function (scope, element, attr) {
        element.html('Hello world');
    }
}

If you must perform the query outside of the directive then it would be possible to use querySelectorAll in modern browers

angular.element(document.querySelectorAll("[my-directive]"));

however you would need to use jquery to support IE8 and backwards

angular.element($("[my-directive]"));

or write your own method as demonstrated here Get elements by attribute when querySelectorAll is not available without using libraries?

like image 70
eddiec Avatar answered Oct 30 '22 13:10

eddiec


You haven't stated where you're looking for the element. If it's within the scope of a controller, it is possible, despite the chorus you'll hear about it not being the 'Angular Way'. The chorus is right, but sometimes, in the real world, it's unavoidable. (If you disagree, get in touch—I have a challenge for you.)

If you pass $element into a controller, like you would $scope, you can use its find() function. Note that, in the jQueryLite included in Angular, find() will only locate tags by name, not attribute. However, if you include the full-blown jQuery in your project, all the functionality of find() can be used, including finding by attribute.

So, for this HTML:

<div ng-controller='MyCtrl'>
    <div>
        <div name='foo' class='myElementClass'>this one</div>
    </div>
</div>

This AngularJS code should work:

angular.module('MyClient').controller('MyCtrl', [
    '$scope',
    '$element',
    '$log',
    function ($scope, $element, $log) {

        // Find the element by its class attribute, within your controller's scope
        var myElements = $element.find('.myElementClass');

        // myElements is now an array of jQuery DOM elements

        if (myElements.length == 0) {
            // Not found. Are you sure you've included the full jQuery?
        } else {
            // There should only be one, and it will be element 0
            $log.debug(myElements[0].name); // "foo"
        }

    }
]);
like image 13
Michael Scheper Avatar answered Oct 30 '22 13:10

Michael Scheper


Your use-case isn't clear. However, if you are certain that you need this to be based on the DOM, and not model-data, then this is a way for one directive to have a reference to all elements with another directive specified on them.

The way is that the child directive can require the parent directive. The parent directive can expose a method that allows direct directive to register their element with the parent directive. Through this, the parent directive can access the child element(s). So if you have a template like:

<div parent-directive>
  <div child-directive></div>
  <div child-directive></div>
</div>

Then the directives can be coded like:

app.directive('parentDirective', function($window) {
  return {
    controller: function($scope) {
      var registeredElements = [];
      this.registerElement = function(childElement) {
        registeredElements.push(childElement);
      }
    }
  };
});

app.directive('childDirective', function() {
  return {
    require: '^parentDirective',
    template: '<span>Child directive</span>',
    link: function link(scope, iElement, iAttrs, parentController) {
      parentController.registerElement(iElement);
    }
   };
});

You can see this in action at http://plnkr.co/edit/7zUgNp2MV3wMyAUYxlkz?p=preview

like image 11
Michal Charemza Avatar answered Oct 30 '22 14:10

Michal Charemza