AngularJS отслеживает изменение DOM
У меня есть одна директива auto-carousel
, которая выполняет итерацию через связанный элемент children.
Однако дети еще не загружены в DOM, потому что их выражения ng-if
еще не были проанализированы.
Как я могу убедиться, что родительская директива знает, что были внесены изменения в это дерево DOM?
<ul class="unstyled" auto-carousel>
<li class="slide" ng-if="name">{{name}}</li>
...
<li class="slide" ng-if="email">{{email}}</li>
</ul>
Я мог бы использовать $timeout
, но это кажется ненадежным. Я мог бы использовать ng-show
вместо ng-if
, но это не отвечает на вопрос, а не то, что мне нужно.
Ответы
Ответ 1
Итак, вот что я сделал:
Я обнаружил, что вы можете передать функцию $scope.$watch
. Оттуда довольно просто вернуть значение выражения, которое вы хотите наблюдать за изменениями. Он будет работать точно так же, как передача ключевой строки для свойства в области.
link: function ($scope, $el, $attrs) {
$scope.$watch(
function () { return $el[0].childNodes.length; },
function (newValue, oldValue) {
if (newValue !== oldValue) {
// code goes here
}
}
);
}
Я смотрю childNodes
, а не children
, потому что в списке childNodes
содержатся элементы, а также текстовые узлы и комментарии. Это бесценно, потому что Angular использует метки комментариев для таких директив, как ng-repeat
, ng-if
, ng-switch
и ng-include
, которые выполняют переключение и изменяют DOM, а children
содержат только элементы.
Ответ 2
Если вам нужно следить за любыми изменениями глубже в элементе dom, MutationObserver - это путь:
.directive('myDirective', function() {
return {
...
link: function(scope, element, attrs) {
var observer = new MutationObserver(function(mutations) {
// your code here ...
});
observer.observe(element[0], {
childList: true,
subtree: true
});
}
};
});
Ответ 3
Я создал директивный модуль для этого angular-dom-events
В вашем случае вы могли бы
<ul class="unstyled" auto-carousel>
<li class="slide" ng-if="name" dom-on-create="nameCreated()">{{name}}</li>
<li class="slide" ng-if="email" dom-on-destroy="emailDestroyed()">{{email}}</li>
</ul>
В настоящее время поддерживается только dom-on-create
и dom-on-destroy
, но имеет более высокую производительность, чем принятый ответ, потому что он будет срабатывать только один раз для каждого события dom, а не повторно проверять обратный вызов $watch.
Ответ 4
Хотя я не думаю, что это с рекомендациями angular, вы можете использовать ng-init, который запускает инициализацию элемента:
<ul class="unstyled" auto-carousel>
<li class="slide" ng-if="name" ng-init="recheck()">{{name}}</li>
<li class="slide" ng-if="email" ng-init="recheck()">{{email}}</li>
</ul>
Ответ 5
Вы можете попытаться скомпилировать содержимое директивы сначала внутри вашей функции ссылок. Например:
angular.module('myApp').directive('autoCarousel', ['$compile', function ($compile) {
return {
templateUrl: 'views/auto-carousel.html',
restrict: 'A',
replace: true,
link: function (scope, element, attr) {
$compile(element.contents())(scope);
// your code goes here
}
}
}]);