2014-01-24 61 views
29

我有一個auto-carousel指令,它通過鏈接元素的子代迭代。AngularJS手錶DOM變化

但是這些孩子還沒有加載到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

根據angularJS文檔,子指令在父指令之前被喜歡。所以ng-if在父指令之前被鏈接。所以解析順序不是你的問題。也許你的數據是異步可用的,所以ng-if在鏈接時沒有被解析。 – Alborz

+0

@Alborz這很有趣。你有鏈接嗎?如果是這樣的話,我有一種感覺,這個指令在兒童元素的模型被填充之前就被鏈接了,我會執行一個測試並回復給你。別忘了我的鏈接! – pilau

+0

@Alborz鏈接功能肯定發生*模型填充後。我甚至使用了額外的'$ scope。$ apply()'。 – pilau

回答

69

因此,這裏是我落得這樣做:

我發現,你可以通過一個函數來$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-switchng-include,它們執行DOM的轉換和更改,而children僅保留元素。

+1

這很好!每次在父代中添加或刪除'input'元素時,我都會遇到需要運行函數的情況。所以,'$ scope。$ watch(function(){return $(「。parent input」)。length;},...'。這很好用,但我想知道性能.. – Elise

+7

那麼,在每個'$ digest'循環中至少要調用一次jQuery查找(在這種情況下,也是一個非常糟糕的查找),這在性能方面非常糟糕,您可以緩存節點,然後使用jQuery的find()以改進 – pilau

+2

我確實喜歡這個,而不是像這樣聽內容長度: scope。$ watch(function(){return element [0] .innerHTML.length;},function(n,o) {/ *做一個操作* /}); –

0

您可以嘗試在鏈接函數中首先編譯指令內容。例如:

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 
     } 
    } 
}]); 
+0

這沒有工作...:/ – pilau

5

我創建了這個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-createdom-on-destroy,但具有更好的性能,然後接受的答案,因爲它只會消防一次每個dom事件,而不是反覆檢查$ watch回調。

+0

正是我在找的東西。謝謝! –

+0

如果你可以修改你的孩子,這不錯,如果你正在等待第三方元素出現 –

1

雖然我不認爲這是與角度的建議,你可以使用NG-初始化的時候觸發時元素的初始化:

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

Typical ..正是我在找什麼,並且文檔告訴我不要使用它.. https:/ /docs.angularjs.org/api/ng/directive/ngInit – commonpike

+0

這是唯一對我有用的東西。在表單動態插入到dom後,我需要運行一些代碼。 –

13

如果你需要注意在元素的更深的任何變化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 
      }); 
     } 
    }; 
}); 
+4

這很有趣,但是需要IE 11。 – IProblemFactory