コンテンツが読み込まれた後に呼び出すAngularJsイベント


163

ページのコンテンツが読み込まれた後に呼び出す関数があります。$ viewContentLoadedについて読みましたが、うまくいきません。私は何かを探しています

document.addEventListener('DOMContentLoaded', function () { 
     //Content goes here 
}, false);

上記の呼び出しは、AngularJsコントローラーでは機能しません。


1
これはうまく機能しますstackoverflow.com/q/14968690/6521116
Kris Roofe

回答:


163

$ viewContentLoadedのドキュメントによると、それは動作するはずです

ngViewコンテンツがリロードされるたびに発生します。

$viewContentLoaded イベントが発行されます。つまり、このイベントを受信するには、親コントローラーが必要です。

<div ng-controller="MainCtrl">
  <div ng-view></div>
</div>

MainCtrlあなたからイベントを聞くことができます

  $scope.$on('$viewContentLoaded', function(){
    //Here your view content is fully loaded !!
  });

デモを確認する


59
このアプローチの問題は、コントローラーがこの時点で完全に初期化されていないことです。
アッシュブルー

12
@Reza正解です。このイベントは、domが追加されたとき、angularがdomの処理を完了する前に発生します。これをテストするには、IDまたはクラスを角度変数として追加し、jQueryを使用して$ viewContentLoadedで見つけます。あなたはそれを見つけることはありません。
Thomas Kekeisen

1
@Rezaはい、Thomasは正しいです。フォーム要素は$ viewContentLoaded内でアクセスできませんsay、$ scope.formName.elementName。$ setValidity( "validateRule"、false); 「TypeError:未定義のプロパティ '
elementName

2
$ rootScopeレベルでも同じことができます。$ scope。$ onの代わりに、$ rootScope。$ onおよびapp.run()ブロック内にある必要があります
Vil

4
ng-repeat複雑なループと条件に基づいてHTML /コンテンツを生成するいくつかのネストされたディレクティブがある場合、このオプションは機能しません。$viewContentLoadedイベントがトリガーされた後でも、レンダリングはしばらく続きます。すべての要素が完全にレンダリングされていることを確認してから、特定のコードを実行するにはどうすればよいですか?フィードバックはありますか?
tarekahf 2017年

104

角度<1.6.X

angular.element(document).ready(function () {
    console.log('page loading completed');
});

角度> = 1.6.X

angular.element(function () {
    console.log('page loading completed');
});

これはapp.js内にありますか?
zcoon

3
controllers.jsで聞くことができます
hariszaman

2
メインのapp.jsファイルでも問題なく動作します。
Loubot、2016年

その答えは私にとってうまくいきます!ただ、「(代わりにangular.elementの非推奨、使用angular.element(コールバック)(ドキュメント).ready(コールバック))準備ができて()」ドキュメント要素ページで見ること
ロベラ

これでうまくいきました。受け入れられた回答アプローチは、コントローラーの内部では機能しません。
Fabiano

76

修正済み-2015.06.09

ディレクティブと次のreadyような角度要素メソッドを使用します。

js

.directive( 'elemReady', function( $parse ) {
   return {
       restrict: 'A',
       link: function( $scope, elem, attrs ) {    
          elem.ready(function(){
            $scope.$apply(function(){
                var func = $parse(attrs.elemReady);
                func($scope);
            })
          })
       }
    }
})

html

<div elem-ready="someMethod()"></div>

またはcontroller-as構文を使用している人のために...

<div elem-ready="vm.someMethod()"></div>

これの利点は、UIを好きなだけ広くまたはきめ細かくすることができ、コントローラーからDOMロジックを削除することです。これが推奨されるAngularの方法であると私は主張します。

同じノードで他のディレクティブが動作している場合は、このディレクティブに優先順位を付ける必要がある場合があります。


これは本当に良い解決策のように見えますが、私はそれを機能させることができませんでした。それはelem.ready( $scope.$apply( readyFunc( $scope ))); なぜそれがそうであるかもしれない考えで窒息しました おそらく角度の更新が起こったのでしょうか?とにかく-それがうまくいけば、それはエレガントなアプローチです。
domoarigato

1
nm、私は問題が何であったかを参照してください。にタイプミスがありましたが、現在のタイプになっているattrs.onReadyはずです。もう1つの問題は、私がそれをファンキーと呼んでいることでした... ...コーヒースクリプトをメモリからJSに変換することで得られるもの。
jusopi

1
特定のケースでは問題ないと思いますが、それに対する私の議論は次のとおりです。一見すると、DOMに表示するテキスト値が返されるという彼のコードの期待は、注意が必要です。ディレクティブの優先順位に関してはタイミングを許可しません$timeout。使用しない限り、コントローラーレベルでスタックします。あなたは明示的にaddtを作成しています。非DOMロジックを実行するためのDOMノード。そのメソッドが$ scope階層のはるか上位にあり、子スコープが継承する場合にのみ再利用できます。NGの観点では見た目が悪いと思います。
jusopi

5
を追加した後、私のために働い$timeout(function() {})elem.ready()。それ以外の場合は、$digest already in progressエラーをスローしていました。とにかく、トンに感謝!私は過去1時間、これに苦労しています。
rkrishnan 2016年

1
$ scopeを掘り下げるのは空のようです。何か案は?
MiloTheGreat

66

{{YourFunction()}}HTML要素の後に追加することで、直接呼び出すことができます。

こちらがPlunker Linkです。


6
提供するソリューションについてもう少し説明を追加して、回答を詳しく説明していただけませんか?
abarisone

そのhtml要素が読み込まれたときに関数を呼び出したいと思います。したがって、上記のようにその関数を呼び出します。私の推測があなたの疑問について正しい場合は、これでうまくいきます。そうでなければ、質問を詳しく説明してください。:)
ブルー

14
このような関数を呼び出すとき。一度呼び出されたか、そうでなければダイジェストサイクルが無限に実行され、エラーが表示されることを確認してください
Ashan

2
私はこのソリューションが好きです。とても簡単です
KamuranSönecek15年

1
これは素晴らしいです-唯一の問題。これを使用すると、関数が5回実行されるようです。カウンターを追加したので、正常に機能していますが、それが発生する理由を誰かが知っているのではないかと思っています。
itchyspacesuit

22

グーグルチャートを処理するときに、このロジックを実装する必要がありました。私がやったことは、コントローラ定義内のhtmlの最後に追加したことです。

  <body>
         -- some html here -- 
--and at the end or where ever you want --
          <div ng-init="FunCall()"></div>
    </body>

その関数では、単にロジックを呼び出します。

$scope.FunCall = function () {
        alert("Called");
}

私はこれを使用していましたが、ページの上部で、initはいくつかのdivが既にロードされている必要があったので、ng-initをページの下部に移動することにより、私の問題を修正しました。
ガーナード2016

私の問題を助けた唯一の答え(jqueryモバイルの空の選択)
kaiser

これは、動的に読み込まれるコントロールに適応し、実装が非常に簡単であるため、本当の答えです。
Jason Sebring

この回答は時間を節約してくれたので、私のユースケースではエレガントで効果的でした
Sello

4
var myM = angular.module('data-module');

myM.directive('myDirect',['$document', function( $document ){

    function link( scope , element , attrs ){

        element.ready( function(){

        } );

        scope.$on( '$viewContentLoaded' , function(){

            console.log(" ===> Called on View Load ") ;

        } );

    }

    return {
        link: link
    };

}] );

上記の方法は私のために働きました


3

Angular jsでJavaScriptバージョンのonloadイベントを呼び出すことができます。このng-loadイベントは、div、span、body、iframe、imgなどのdom要素に適用できます。次に、既存のプロジェクトにng-loadを追加するためのリンクを示します。

Angular jsのng-loadをダウンロードする

読み込まれた後のiframeの例を以下に示します。 されると、コントローラでtestCallbackFunctionが呼び出されます。

JS

    // include the `ngLoad` module
    var app = angular.module('myApp', ['ngLoad']);
    app.controller('myCtrl', function($scope) {
        $scope.testCallbackFunction = function() {
          //TODO : Things to do once Element is loaded
        };

    });  

HTML

  <div ng-app='myApp' ng-controller='myCtrl'> 
      <iframe src="test.html" ng-load callback="testCallbackFunction()">  
  </div>

OPが問題を解決する方法を示すサンプルコードを追加してください
jro

@jro ansを更新しました。それがお
役に立てば幸いです

2

$ digestが既に進行中のエラーを受け取っている場合、これは役立つかもしれません:

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

                if(!$scope.$$phase) {
                    $scope.$apply(function(){
                        var func = $parse(attrs.elemReady);
                        func($scope);
                    })
                }
                else {

                    var func = $parse(attrs.elemReady);
                    func($scope);
                }

            })
        }
    }

0

ページ読み込み後に実行するには、イベントリスナーをウィンドウ読み込みイベントに設定することで部分的に満たす必要があります

window.addEventListener("load",function()...)

内部 module.run(function()...)angularの、モジュールの構造と依存関係にすべてアクセスできます。

次のことが可能broadcastemitコミュニケーションブリッジのためのイベント。

例えば:

  • モジュールセットonloadイベントとビルドロジック
  • モジュールは、ロジックが必要なときにイベントをコントローラーにブロードキャストします
  • コントローラーは、モジュールのonloadプロセスに基づいて独自のロジックをリッスンして実行します。

0

私は{{myFunction()}}テンプレートで使用していましたが、コントローラーの内部使用する別の方法を見つけました$timeout。私はそれを共有すると思いましたが、私にとってはうまくいきます。

angular.module('myApp').controller('myCtrl', ['$timeout',
function($timeout) {
var self = this;

self.controllerFunction = function () { alert('controller function');}

$timeout(function () {
    var vanillaFunction = function () { alert('vanilla function'); }();
    self.controllerFunction();
});

}]);

私はここですべての答えを試しましたが、何らかの理由で$ timeoutが私にとってうまくいった唯一のものです。理由はわかりませんが、ng-includeとサービス開始のタイミングに関係している可能性があります。
Drellgor 2017年

{{myFunction()}}にプラスワンを追加しました
commonpike

0

特定の要素を完全にロードする場合は、その要素でng-initを使用します。

例えば <div class="modal fade" id="modalFacultyInfo" role="dialog" ng-init="initModalFacultyInfo()"> ..</div>

initModalFacultyInfo()関数がコントローラーに存在する必要があります。


0

ネストされたビューがある場合、ネストされたすべてのビューに対して$ viewContentLoadedがトリガーされることがわかりました。最終的な$ viewContentLoadedを見つけるために、この回避策を作成しました。Prerenderの要求に応じて$ window.prerenderReadyを設定することで問題なく動作するようです(メインのapp.jsの.run()に移動します)。

// Trigger $window.prerenderReady once page is stable
// Note that since we have nested views - $viewContentLoaded is fired multiple
// times and we need to go around this problem
var viewContentLoads = 0;
var checkReady = function(previousContentLoads) {
  var currentContentLoads = Number(viewContentLoads) + 0; // Create a local copy of the number of loads
  if (previousContentLoads === currentContentLoads) { // Check if we are in a steady state
    $window.prerenderReady = true; // Raise the flag saying we are ready
  } else {
    if ($window.prerenderReady || currentContentLoads > 20) return; // Runaway check
    $timeout(function() {checkReady(currentContentLoads);}, 100); // Wait 100ms and recheck
  }
};
$rootScope.$on('$stateChangeSuccess', function() {
  checkReady(-1); // Changed the state - ready to listen for end of render
});
$rootScope.$on('$viewContentLoaded', function() {
  viewContentLoads ++;
});

0
var myTestApp = angular.module("myTestApp", []); 
myTestApp.controller("myTestController", function($scope, $window) {
$window.onload = function() {
 alert("is called on page load.");
};
});

このコードは質問に答えることがありますが、このコードが質問に答える理由や方法に関する追加のコンテキストを提供すると、長期的な価値が向上します。
rollstuhlfahrer 2018

0

私のために働く解決策は次のとおりです

app.directive('onFinishRender', ['$timeout', '$parse', function ($timeout, $parse) {
    return {
        restrict: 'A',
        link: function (scope, element, attr) {
            if (scope.$last === true) {
                $timeout(function () {
                    scope.$emit('ngRepeatFinished');
                    if (!!attr.onFinishRender) {
                        $parse(attr.onFinishRender)(scope);
                    }
                });
            }

            if (!!attr.onStartRender) {
                if (scope.$first === true) {
                    $timeout(function () {
                        scope.$emit('ngRepeatStarted');
                        if (!!attr.onStartRender) {
                            $parse(attr.onStartRender)(scope);
                        }
                    });
                }
            }
        }
    }
}]);

コントローラコードは次のとおりです

$scope.crearTooltip = function () {
     $('[data-toggle="popover"]').popover();
}

HTMLコードは次のとおりです

<tr ng-repeat="item in $data" on-finish-render="crearTooltip()">

-31

setIntervalコンテンツが読み込まれるのを待つために使用します。これが問題の解決に役立つことを願っています。

var $audio = $('#audio');
var src = $audio.attr('src');
var a;
a = window.setInterval(function(){
    src = $audio.attr('src');
    if(src != undefined){
        window.clearInterval(a);
        $('audio').mediaelementplayer({
            audioWidth: '100%'
        });
    }
}, 0);

13
人々はまだ2016年のsetInterval解決策として推奨していますか?
Zachary Dahan 2016年

しかし、agularに単純なAPIはありません...どのようにそれを行うのですか?
Piotr Kula
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.