AngularJS watch DOM change

纵然是瞬间 提交于 2019-11-27 01:17:34

So here's what I ended up doing:

I discovered you could pass a function to $scope.$watch. From there, it's pretty straightforward to return the value of the expression you want to watch for changes. It will work exactly like passing a key string for a property on the scope.

link: function ($scope, $el, $attrs) {
  $scope.$watch(
    function () { return $el[0].childNodes.length; },
    function (newValue, oldValue) {
      if (newValue !== oldValue) {
        // code goes here
      }
    }
  );
}

I am watching childNodes, not children, because the childNodes list holds elements as well as text nodes and comments. This is priceless because Angular uses comment placeholders for directives like ng-repeat, ng-if, ng-switch and ng-include which perform transclusion and alter the DOM, while children only holds elements.

If you need to watch for any changes deeper in the element's dom, MutationObserver is the way to go :

.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
            });
        }
    };
});

I created a directive module for this angular-dom-events

In your case you could

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

Currently only supports dom-on-create and dom-on-destroy, but has better performance then the accepted answer because it will only fire once for each dom event, rather than repeatedly check the $watch callback.

Although I don't think it is with angular's recommendations, you could use ng-init which fires upon the initialization of the element:

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

You could try to compile the directive contents first inside your link function. For example:

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
        }
    }
}]);
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!