Подтвердить что ты не робот

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, но это не отвечает на вопрос, а не то, что мне нужно.

4b9b3361

Ответ 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
        }
    }
}]);