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?

7 Answers 7

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.

Sign up to request clarification or add additional context in comments.

4 Comments

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?
So to clarify the fix for me was move the <script src="jquery"> tag above the angular <script src="angular"> tag.
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 working rev: link
I used jQuery(elm).find('#someid')
26

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.

1 Comment

This should be the accepted anwser. It doesn't use jQuery and does not impose the element we want to find has an ID.
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

6 Comments

This is BAD! getElementById will search the entire HTML document beginning from the root, and is not restricted to search in the template
i find var $el = $('div.robotarm', '#container'); more readable given the context.
@Spock maybe you could use jsPerf to demonstratet? getElementById is internally indexed, so it doesn't scan the DOM.
@Karl > I think I was wrong. getElementByID speed does not get affected by this, if you specifically search for an ID.
Thanks for clarifying @Spock, it will help others too. Nice to see a humble person on here.
|
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');

Comments

1

I used

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

to get children of the current element

1 Comment

jqLite does not accept a selector for children(), you just get all the direct child elements.
-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;

1 Comment

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.
-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/

1 Comment

This one doesn't work as you might expect: jsfiddle.net/FZGKA/167 it's just adding the class to all children, the selector doesn't matter

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.