45

I am having trouble with angularjs directives finding child DOM elements with the injected angular element.

For example I have a directive like so:

myApp.directive('test', function () {
    return {
        restrict: "A",
        link: function (scope, elm, attr) {
            var look = elm.find('#findme');
             elm.addClass("addedClass");
            console.log(look);
        }
    };
});

and HTML such as :

<div ng-app="myApp">
    <div test>TEST Div
        <div id="findme"></div>
    </div>
</div>

I have access to the element which is proffed by adding a class to it. However attempting to access a child element produces an empty array in the var look.

JSFiddle demo is here.

Why is something so trivial not working properly?

isherwood
  • 58,414
  • 16
  • 114
  • 157
Ray Garner
  • 932
  • 1
  • 10
  • 18

7 Answers7

76

From the docs on angular.element:

find() - Limited to lookups by tag name

So if you're not using jQuery with Angular, but relying upon its jqlite implementation, you can't do elm.find('#someid').

You do have access to children(), contents(), and data() implementations, so you can usually find a way around it.

satchmorun
  • 12,487
  • 2
  • 41
  • 27
  • 5
    Thanks. In my case i was actually including JQuery, however it was being included after angularjs which is apparently what the problem is. Also I did not recognize that find was not available in JQlite it does not specify that in the docs! Just says "Limited to lookups by tag name" which I thought meant id tag name? – Ray Garner Feb 14 '13 at 01:06
  • 3
    So to clarify the fix for me was move the – Ray Garner Feb 14 '13 at 01:12
  • Last bit of clarification You can see here what I had to do to get this to work in jsfiddle. I had to import jquery first then added angularjs as a resource to get it to work. Non-working rev: [link](http://jsfiddle.net/raygarner/FZGKA/7/) working rev: [link](http://jsfiddle.net/raygarner/FZGKA/8/) – Ray Garner Feb 14 '13 at 01:14
  • I used jQuery(elm).find('#someid') – Cherven Apr 21 '15 at 19:07
27

You can easily solve that in 2 steps:

1- Reach the child element using querySelector like that: var target = element[0].querySelector('tbody tr:first-child td')

2- Transform it to an angular.element object again by doing: var targetElement = angular.element(target)

You will then have access to all expected methods on the targetElement variable.

Felippe Nardi
  • 615
  • 7
  • 12
  • 1
    This should be the accepted anwser. It doesn't use jQuery and does not impose the element we want to find has an ID. – kboom Oct 13 '15 at 06:50
13

Before the days of jQuery you would use:

   document.getElementById('findmebyid');

If this one line will save you an entire jQuery library, it might be worth while using it instead.

For those concerned about performance: Beginning your selector with an ID is always best as it uses native function document.getElementById.

// Fast:
$( "#container div.robotarm" );

// Super-fast:
$( "#container" ).find( "div.robotarm" );

http://learn.jquery.com/performance/optimize-selectors/

jsPerf http://jsperf.com/jquery-selector-benchmark/32

Zymotik
  • 6,412
  • 3
  • 39
  • 48
9

find() - Limited to lookups by tag name you can see more information https://docs.angularjs.org/api/ng/function/angular.element

Also you can access by name or id or call please following example:

angular.element(document.querySelector('#txtName')).attr('class', 'error');
leocborges
  • 4,799
  • 5
  • 32
  • 38
user3454062
  • 171
  • 2
  • 1
1

I used

elm.children('.class-name-or-whatever') 

to get children of the current element

simonpkerr
  • 133
  • 1
  • 4
  • 10
    jqLite does not accept a selector for children(), you just get all the direct child elements. – Frankey Jun 17 '15 at 19:08
-2

If anyone is looking to grab the scope off of a 'controller as' element,.. something like this:

<div id="firstctrl" ng-controller="firstCtrl as vm">  

use the following:

var vm = angular.element(document.querySelector('#firstctrl')).scope().vm;
Post Impatica
  • 14,999
  • 9
  • 67
  • 78
  • Not sure how this is relevant. Can't see any mention about getting child scope or controllerAs syntax. Might have missed something and happy to be proven wrong. – perry May 03 '16 at 06:06
-3

You can do it like this:

 var myApp = angular.module('myApp', [])
  .controller('Ctrl', ['$scope', function($scope) {
     $scope.aaa = 3432
 }])
 .directive('test', function () {
    return {
       link: function (scope, elm, attr) {
           var look = elm.children('#findme').addClass("addedclass");
           console.log(look);
        }
   };
});

<div ng-app="myApp" ng-controller="Ctrl">
   <div test>TEST Div
      <div id="findme">{{aaa}}</div>
   </div>
</div>

http://jsfiddle.net/FZGKA/133/

ST80
  • 3,565
  • 16
  • 64
  • 124
  • This one doesn't work as you might expect: http://jsfiddle.net/FZGKA/167/ it's just adding the class to all children, the selector doesn't matter – ShaneTheKing Dec 30 '15 at 20:34