简体   繁体   中英

Run Javascript AFTER Angular Has Finished Loading All Views

I am building a web application using Angular, and I am trying to find a way to wait until all of the data-ng-include elements have been evaluated and the includes finished loading. For instance the menu is a view that is loaded, as is the main content for each page, so at the very least there are two data-ng-include s that get evaluated and loaded. On top of that the menu include has nested data-ng-repeat s that build out my menu. I need a way to initiate script AFTER all of these includes and any angular functions inside them have been loaded and the DOM is ACTUALLY ready.

Is there any event that gets fired when Angular has finished setting up the page?

The implementation of AnguarJS is basic and we are basically using it for templating via use of data-ng-include. Each page is a view (not an angular view, just an html file), loaded via data-ng-include, with the header and footer above and below it. The header also dynamically loads a global view (again not an angular view) html file that includes angular.

So far the menu is the only thing using AngularJS for anything other than templating. It uses it to create a menu using a JSON object that is dynamically generated by JSP and inserted into the DOM that is returned from the server.

In order to make life easier for the front-end guys, any kind of repeated JavaScript functionality is coded out into modules, which are detected on page load and loaded dynamically using a data-features attribute on the element the JavaScript functionality needs to be attached to.

For instance, you may have <div id="mySubMenu" data-features="subMenu"></div> . On page load, each element with a data-features element is detected, and the associated JS module loaded, in this case we would load /scripts/modules/subMenu.js .

What I need is a way to delay running this feature detection and attachment until all of the elements resulting from an include or other angular function are on the page and ready to be manipulated, especially since there may be elements with data-features attributes inside those includes.

Someone elsewhere had mentioned putting a controller on the body and putting nothing side of it but:

$scope.$on('$viewContentLoaded', function() {
    // Init Features Here
});

That did not work, so I am here looking for other options.

I ended up going with Theo's solution in this question: Sending event when angular.js finished loading

on content loaded:

$rootScope.$on('$includeContentLoaded', function() {
    //do your will
});

on content requested:

$rootScope.$on('$includeContentRequested', function() {
    //...
});

I am certain that this is not the correct way to do it but....

Putting the below function in my view controller, ran the function after the view had loaded in my application. I believe that the function is run in the next digest cycle following the view load (correct me here if wrong), so it is run once the page is formed.

setTimeout(function(){
  //do this after view has loaded :)
  console.log('success!');
}, 0);

Its possible you could chain these together via callbacks and/or use an async parallel library to execute another function, after each of the views setTimeouts had returned.

I think the appropiate answer is NO. You have to change the way you are looking at your app and Model and adapt it to the "angular way". Most likely there is a healthier way to achieve what you need. If you need to attach events to elements probably you may want to use a directive but of course I do not have enough information to judge at this stage what is best.

angular.module along with directives is a good option to explore.

Here is a plunker demo on how to use both with a JQUERY plug in:

http://plnkr.co/edit/WGdNEM?p=preview

Here is a an example with a directive on a separate file:

http://plnkr.co/edit/YNBSWPLeWqsfGvOTwsMB?p=preview

You can use a JQuery Promise, and fulfill this promise within your angular root controller. Setup the promise before the angular controller or jquery code runs:

var AppReadyDeferred = $.Deferred();
var AppReadyPromise = AppReadyDeferred.promise();

Inside your angular controller once everything is ready, do

AppReadyDeferred.resolve();

And in your jQuery code wait for it to be resolved

window.AppReadyPromise.done(() => {
  // Angular is ready to go!;
});

Use ng-cloak to delay templates being shown before compilation. You can also add a hidden field as the very last child to your html element that has ng-cloak (better to use it in body tag or wherever your ng-app starts) and then you can check for existence of this hidden element in an interval loop

Your hidden field part would be like this

<div ng-include="'ngtplhidden'"></hidden>
<script type="text/ng-template" id="ngtplhidden">
<span id="elemidToCheckInAnIntervalFunc"></span>
</script>

You can try using document.onreadystatechange

document.onreadystatechange = x => {
    console.log('ready!');
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM