How to run function in AngularJS controller on document ready?

JavascriptAngularjsOnload

Javascript Problem Overview


I have a function within my angular controller, I'd like this function to be run on document ready but I noticed that angular runs it as the dom is created.

 function myController($scope)
 {
     $scope.init = function()
     {
        // I'd like to run this on document ready
     }

     $scope.init(); // doesn't work, loads my init before the page has completely loaded
 }

Anyone know how I can go about this?

Javascript Solutions


Solution 1 - Javascript

We can use the angular.element(document).ready() method to attach callbacks for when the document is ready. We can simply attach the callback in the controller like so:

angular.module('MyApp', [])

.controller('MyCtrl', [function() {
    angular.element(document).ready(function () {
        document.getElementById('msg').innerHTML = 'Hello';
    });
}]);

http://jsfiddle.net/jgentes/stwyvq38/1/

Solution 2 - Javascript

See this post https://stackoverflow.com/questions/15458609/angular-js-how-to-execute-function-on-page-load
For fast lookup:

// register controller in html
<div data-ng-controller="myCtrl" data-ng-init="init()"></div>

// in controller
$scope.init = function () {
    // check if there is query in url
    // and fire search in case its value is not empty
};

This way, You don't have to wait till document is ready.

Solution 3 - Javascript

Angular has several timepoints to start executing functions. If you seek for something like jQuery's

$(document).ready();

You may find this analog in angular to be very useful:

$scope.$watch('$viewContentLoaded', function(){
    //do something
});

This one is helpful when you want to manipulate the DOM elements. It will start executing only after all te elements are loaded.

UPD: What is said above works when you want to change css properties. However, sometimes it doesn't work when you want to measure the element properties, such as width, height, etc. In this case you may want to try this:

$scope.$watch('$viewContentLoaded', 
    function() { 
        $timeout(function() {
            //do something
        },0);    
});

Solution 4 - Javascript

> Angular initializes automatically upon DOMContentLoaded event or when > the angular.js script is evaluated if at that time document.readyState > is set to 'complete'. At this point Angular looks for the ng-app > directive which designates your application root.

https://docs.angularjs.org/guide/bootstrap

This means that the controller code will run after the DOM is ready.

Thus it's just $scope.init().

Solution 5 - Javascript

The answer

$scope.$watch('$viewContentLoaded', 
    function() { 
        $timeout(function() {
            //do something
        },0);    
});

is the only one that works in most scenarios I tested. In a sample page with 4 components all of which build HTML from a template, the order of events was

$document ready
$onInit
$postLink
(and these 3 were repeated 3 more times in the same order for the other 3 components)
$viewContentLoaded (repeated 3 more times)
$timeout execution (repeated 3 more times)

So a $document.ready() is useless in most cases since the DOM being constructed in angular may be nowhere near ready.

But more interesting, even after $viewContentLoaded fired, the element of interest still could not be found.

Only after the $timeout executed was it found. Note that even though the $timeout was a value of 0, nearly 200 milliseconds elapsed before it executed, indicating that this thread was held off for quite a while, presumably while the DOM had angular templates added on a main thread. The total time from the first $document.ready() to the last $timeout execution was nearly 500 milliseconds.

In one extraordinary case where the value of a component was set and then the text() value was changed later in the $timeout, the $timeout value had to be increased until it worked (even though the element could be found during the $timeout). Something async within the 3rd party component caused a value to take precedence over the text until sufficient time passed. Another possibility is $scope.$evalAsync, but was not tried.

I am still looking for that one event that tells me the DOM has completely settled down and can be manipulated so that all cases work. So far an arbitrary timeout value is necessary, meaning at best this is a kludge that may not work on a slow browser. I have not tried JQuery options like liveQuery and publish/subscribe which may work, but certainly aren't pure angular.

Solution 6 - Javascript

I had a similar situation where I needed to execute a controller function after the view was loaded and also after a particular 3rd-party component within the view was loaded, initialized, and had placed a reference to itself on $scope. What ended up working for me was to setup a watch on this scope property and firing my function only after it was initialized.

// $scope.myGrid property will be created by the grid itself
// The grid will have a loadedRows property once initialized

$scope.$watch('myGrid', function(newValue, oldValue) {
    if (newValue && newValue.loadedRows && !oldValue) {
        initializeAllTheGridThings();
    }
});

The watcher is called a couple of times with undefined values. Then when the grid is created and has the expected property, the initialization function may be safely called. The first time the watcher is called with a non-undefined newValue, oldValue will still be undefined.

Solution 7 - Javascript

Here's my attempt inside of an outer controller using coffeescript. It works rather well. Please note that settings.screen.xs|sm|md|lg are static values defined in a non-uglified file I include with the app. The values are per the Bootstrap 3 official breakpoints for the eponymous media query sizes:

xs = settings.screen.xs // 480
sm = settings.screen.sm // 768
md = settings.screen.md // 992
lg = settings.screen.lg // 1200

doMediaQuery = () ->
    
    w = angular.element($window).width()

    $scope.xs = w < sm
    $scope.sm = w >= sm and w < md
    $scope.md = w >= md and w < lg
    $scope.lg = w >= lg
    $scope.media =  if $scope.xs 
                        "xs" 
                    else if $scope.sm
                        "sm"
                    else if $scope.md 
                        "md"
                    else 
                        "lg"

$document.ready () -> doMediaQuery()
angular.element($window).bind 'resize', () -> doMediaQuery()

Solution 8 - Javascript

If you're getting something like getElementById call returns null, it's probably because the function is running, but the ID hasn't had time to load in the DOM.

Try using Will's answer (towards the top) with a delay. Example:

angular.module('MyApp', [])

.controller('MyCtrl', [function() {
    $scope.sleep = (time) => {
        return new Promise((resolve) => setTimeout(resolve, time));
    };
    angular.element(document).ready(function () {
        $scope.sleep(500).then(() => {        
            //code to run here after the delay
        });
    });
}]);

Solution 9 - Javascript

Why not try with what angular docs mention [https://docs.angularjs.org/api/ng/function/angular.element][1]. > angular.element(callback)

I've used this inside my $onInit(){...} function.

 var self = this;

 angular.element(function () {
        var target = document.getElementsByClassName('unitSortingModule');
        target[0].addEventListener("touchstart", self.touchHandler, false);
        ...
    });

This worked for me. [1]: https://docs.angularjs.org/api/ng/function/angular.element

Solution 10 - Javascript

$scope.$on('$ViewData', function(event) {
//Your code.
});

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionShai UIView Question on Stackoverflow
Solution 1 - JavascriptWillView Answer on Stackoverflow
Solution 2 - JavascriptvineshView Answer on Stackoverflow
Solution 3 - JavascriptAlex LinkView Answer on Stackoverflow
Solution 4 - JavascriptWill MView Answer on Stackoverflow
Solution 5 - JavascriptWray SmallwoodView Answer on Stackoverflow
Solution 6 - JavascriptMikeyMView Answer on Stackoverflow
Solution 7 - JavascriptakutzView Answer on Stackoverflow
Solution 8 - JavascriptMr. GreenView Answer on Stackoverflow
Solution 9 - JavascriptMahibView Answer on Stackoverflow
Solution 10 - JavascriptShreyansh KumarView Answer on Stackoverflow