AngularJs event to call after content is loaded

2019-01-01 10:19发布

问题:

I have a function which I want to call after page content is loaded. I read about $viewContentLoaded and it doesn\'t work for me. I am looking for something like

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

Above call doesn\'t work for me in AngularJs controller.

回答1:

According to documentation of $viewContentLoaded, it supposed to work

Emitted every time the ngView content is reloaded.

$viewContentLoaded event is emitted that means to receive this event you need a parent controller like

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

From MainCtrl you can listen the event

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

Check the Demo



回答2:

Angular < 1.6.X

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

Angular >= 1.6.X

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


回答3:

fixed - 2015.06.09

Use a directive and the angular element ready method like so:

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>

or for those using controller-as syntax...

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

The benefit of this is that you can be as broad or granular w/ your UI as you like and you are removing DOM logic from your controllers. I would argue this is the recommended Angular way.

You may need to prioritize this directive in case you have other directives operating on the same node.



回答4:

You can directly call it by adding {{YourFunction()}} after HTML element.

Here is a Plunker Link.



回答5:

I had to implement this logic while handling with google charts. what i did was that at the end of my html inside controller definition i added.

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

and in that function simply call your logic.

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


回答6:

If you\'re getting a $digest already in progress error, this might help:

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

            })
        }
    }


回答7:

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

}] );

Above method worked for me



回答8:

I was using {{myFunction()}} in the template but then found another way here using $timeout inside the controller. Thought I\'d share it, works great for me.

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

}]);


回答9:

Running after the page load should partially be satisfied by setting an event listener to the window load event

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

Inside the module.run(function()...) of angular you will have all access to the module structure and dependencies.

You can broadcast and emit events for communications bridges.

For example:

  • module set onload event and build logic
  • module broadcast event to controllers when logic required it
  • controllers will listen and execute their own logic based on module onload processes.


回答10:

If you want certain element to completely loaded, Use ng-init on that element .

e.g. <div class=\"modal fade\" id=\"modalFacultyInfo\" role=\"dialog\" ng-init=\"initModalFacultyInfo()\"> ..</div>

the initModalFacultyInfo() function should exist in the controller.



回答11:

I found that if you have nested views - $viewContentLoaded gets triggered for every of the nested views. I\'ve created this workaround to find the final $viewContentLoaded. Seems to work alright for setting $window.prerenderReady as required by Prerender (goes into .run() in the main app.js):

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


回答12:

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


回答13:

The solution that work for me is the following

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

Controller code is the following

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

Html code is the following

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


回答14:

I use setInterval to wait for the content loaded. I hope this can help you to solve that problem.

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