web-dev-qa-db-ja.com

DOMのレンダリングが完了した後にディレクティブを実行するにはどうすればよいですか?

(Angular JS docsを読むことで)解決策がない明らかな単純な問題があります。

DOM内のコンテナの高さを定義するために、他のDOM要素の高さに基づいていくつかの計算を行うAngular JSディレクティブがあります。

これに類似した何かがディレクティブ内で行われています:

return function(scope, element, attrs) {
    $('.main').height( $('.site-header').height() -  $('.site-footer').height() );
}

問題は、ディレクティブの実行時に$('site-header')が見つからず、必要なjQueryラップDOM要素の代わりに空の配列が返されることです。

ディレクティブ内で使用できるコールバックがあり、DOMがロードされた後にのみ実行され、通常のjQueryセレクタースタイルクエリを介して他のDOM要素にアクセスできますか?

114
Jannis

それはあなたの$( 'site-header')がどのように構築されるかによります。

$ timeout を0遅延で使用することができます。何かのようなもの:

return function(scope, element, attrs) {
    $timeout(function(){
        $('.main').height( $('.site-header').height() -  $('.site-footer').height() );
    });        
}

仕組みの説明: onetwo

ディレクティブに$timeoutを挿入することを忘れないでください:

.directive('sticky', function($timeout)
136
Artem Andreev

ここに私がそれをする方法があります:

app.directive('example', function() {

    return function(scope, element, attrs) {
        angular.element(document).ready(function() {
                //MANIPULATE THE DOM
        });
    };

});
43
rjm226

おそらく著者は私の答えをもう必要としないでしょう。それでも、完全を期すために、他のユーザーが便利だと感じるかもしれません。最も簡単で簡単な解決策は、返される関数の本体内で$(window).load()を使用することです。 (または、document.readyを使用することもできます。すべての画像が必要かどうかは本当に異なります)。

私の謙虚な意見で$timeoutを使用することは非常に弱いオプションであり、場合によっては失敗する可能性があります。

使用する完全なコードは次のとおりです。

.directive('directiveExample', function(){
   return {
       restrict: 'A',
       link: function($scope, $elem, attrs){

           $(window).load(function() {
               //...JS here...
           });
       }
   }
});
37
jnardiello

ngcontentloadedイベントがあります。使用できると思います

.directive('directiveExample', function(){
   return {
       restrict: 'A',
       link: function(scope, elem, attrs){

                $$window = $ $window


                init = function(){
                    contentHeight = elem.outerHeight()
                    //do the things
                }

                $$window.on('ngcontentloaded',init)

       }
   }
});
8
sunderls

外部リソースのために$ timeoutを使用できず、タイミングに関する特定の問題のためにディレクティブを使用できない場合は、ブロードキャストを使用します。

目的の外部リソースまたは長時間実行されるコントローラー/ディレクティブが完了した後、$scope.$broadcast("variable_name_here");を追加します。

次に、外部リソースがロードされた後に以下を追加します。

$scope.$on("variable_name_here", function(){ 
   // DOM manipulation here
   jQuery('selector').height(); 
}

たとえば、遅延HTTPリクエストの約束。

MyHttpService.then(function(data){
   $scope.MyHttpReturnedImage = data.image;
   $scope.$broadcast("imageLoaded");
});

$scope.$on("imageLoaded", function(){ 
   jQuery('img').height(80).width(80); 
}
5
JSV

同様の問題があったので、ここで自分の解決策を共有したいと思います。

次のHTMLがあります。

<div data-my-directive>
  <div id='sub' ng-include='includedFile.htm'></div>
</div>

問題:親divのディレクティブのリンク関数で、子div#subをjqueryしたかった。しかし、ディレクティブのリンク関数が実行されたときにng-includeが終了していなかったため、空のオブジェクトが与えられました。そこで、最初に$ timeoutで汚い回避策を行いましたが、これは機能しましたが、遅延パラメーターはクライアントの速度に依存していました(誰もそれを好みません)。

動作するが汚れている:

app.directive('myDirective', [function () {
    var directive = {};
    directive.link = function (scope, element, attrs) {
        $timeout(function() {
            //very dirty cause of client-depending varying delay time 
            $('#sub').css(/*whatever*/);
        }, 350);
    };
    return directive;
}]);

これがクリーンなソリューションです。

app.directive('myDirective', [function () {
    var directive = {};
    directive.link = function (scope, element, attrs) {
        scope.$on('$includeContentLoaded', function() {
            //just happens in the moment when ng-included finished
            $('#sub').css(/*whatever*/);
        };
    };
    return directive;
}]);

たぶんそれは誰かを助ける。

1
jaheraho