Метод jQuery find() не работает в директиве AngularJS

У меня возникают проблемы с директивами angularjs, которые находят дочерние элементы DOM с введенным элементом angular.

Например, у меня есть такая директива:

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

и HTML, например:

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

У меня есть доступ к элементу, который создается путем добавления к нему класса. Однако попытка доступа к дочернему элементу приводит к пустому массиву в виде var.

демонстрация JSFiddle здесь.

Почему что-то настолько тривиальное не работает должным образом?


person Ray Garner    schedule 14.02.2013    source источник


Ответы (7)


Из документов на angular.element:

find() — ограничен поиском по имени тега

Поэтому, если вы не используете jQuery с Angular, а полагаетесь на его реализацию jqlite, вы не можете сделать elm.find('#someid').

У вас есть доступ к реализациям children(), contents() и data(), так что обычно вы можете найти способ обойти это.

person satchmorun    schedule 14.02.2013
comment
Спасибо. В моем случае я на самом деле включал JQuery, однако он включался после angularjs, что, по-видимому, и является проблемой. Также я не узнал, что find не был доступен в JQlite, это не указано в документах! Просто говорит, что ограничен поиском по имени тега, который, как я думал, означает имя тега id? - person Ray Garner; 14.02.2013
comment
Поэтому, чтобы прояснить исправление для меня, было переместить тег ‹script src=jquery› над тегом angular ‹script src=angular›. - person Ray Garner; 14.02.2013
comment
Последнее уточнение. Здесь вы можете увидеть, что мне пришлось сделать, чтобы заставить это работать в jsfiddle. Мне пришлось сначала импортировать jquery, а затем добавить angularjs в качестве ресурса, чтобы заставить его работать. Нерабочая версия: ссылка рабочая версия: ссылка - person Ray Garner; 14.02.2013
comment
Я использовал jQuery(elm).find('#someid') - person Cherven; 21.04.2015

Вы можете легко решить это в 2 шага:

1- Достичь дочернего элемента с помощью querySelector следующим образом: var target = element[0].querySelector('tbody tr:first-child td')

2- Снова преобразуйте его в объект angular.element, выполнив: var targetElement = angular.element(target)

После этого у вас будет доступ ко всем ожидаемым методам переменной targetElement.

person Felippe Nardi    schedule 23.06.2015
comment
Это должен быть принятый ответ. Он не использует jQuery и не навязывает идентификатор элемента, который мы хотим найти. - person kboom; 13.10.2015

До дней jQuery вы использовали:

   document.getElementById('findmebyid');

Если эта одна строка сэкономит вам всю библиотеку jQuery, возможно, стоит использовать ее вместо этого.

Для тех, кто беспокоится о производительности: всегда лучше начинать свой селектор с идентификатора, поскольку он использует встроенную функцию 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

person Zymotik    schedule 04.03.2014
comment
Это плохо! getElementById будет искать весь документ HTML, начиная с корня, и не ограничивается поиском в шаблоне. - person Spock; 23.07.2014
comment
я нахожу var $el = $('div.robotarm', '#container'); более читаемым, учитывая контекст. - person Rafael Herscovici; 01.12.2014
comment
@Spock, может быть, вы могли бы использовать jsPerf для демонстрации? getElementById индексируется внутри, поэтому не сканирует DOM. - person Zymotik; 17.08.2015
comment
@Spock Хотите поделиться, как это сделать? - person basickarl; 04.10.2015
comment
@Karl › Думаю, я ошибался. На скорость getElementByID это не влияет, если вы специально ищете ID. - person Spock; 23.10.2015
comment
Спасибо за разъяснение @Spock, это поможет и другим. Приятно видеть скромного человека здесь. - person Zymotik; 23.10.2015

find() — Ограничен поиском по имени тега, вы можете увидеть дополнительную информацию https://docs.angularjs.org/api/ng/function/angular.element

Также вы можете получить доступ по имени или идентификатору или позвонить, пожалуйста, следующий пример:

angular.element(document.querySelector('#txtName')).attr('class', 'error');
person user3454062    schedule 12.09.2014

я использовал

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

чтобы получить дочерние элементы текущего элемента

person simonpkerr    schedule 23.01.2015
comment
jqLite не принимает селектор для детей(), вы просто получаете все прямые дочерние элементы. - person Frankey; 17.06.2015

Если кто-то хочет захватить область действия элемента «контроллер как», .. что-то вроде этого:

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

используйте следующее:

var vm = angular.element(document.querySelector('#firstctrl')).scope().vm;
person Post Impatica    schedule 21.01.2016
comment
Не уверен, насколько это актуально. Не вижу никаких упоминаний о получении дочерней области или синтаксиса controllerAs. Может быть, что-то пропустил и рад, что оказался неправ. - person perry; 03.05.2016

Вы можете сделать это следующим образом:

 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/

person ST80    schedule 24.06.2015
comment
Этот вариант работает не так, как вы могли ожидать: jsfiddle.net/FZGKA/167 он просто добавляет класс для всех детей, селектор не имеет значения - person ShaneTheKing; 30.12.2015