What is the best way to detect the end of html loading by ng–include
? I want to write some code that runs when it has finished loading.
There are two ways to detect when ng-include
finished loading, depending on your need:
1) via onload attribute - for inline expressions. Ex:
<div ng-include="'template.html'" onload="loaded = true"></div>
2) via an event $includeContentLoaded that ng-include
emits - for app-wide handling. Ex:
app.run(function($rootScope){
$rootScope.$on("$includeContentLoaded", function(event, templateName){
//...
});
});
when it finishes loading the content
You can use this code:
$scope.$on('$includeContentLoaded', function () {
// it has loaded!
});
you can use onload
for it as below
<div ng-include=".." onload="finishLoading()"></div>
in controller,
$scope.finishLoading = function() {
}
after loading the ng-include
finishLoading
scope function will call.
here is the working Demo Plunker
There is an alternative for that only using JS call stack tricks. put ng-init="eventName"
on the desired element. After that, declare the event on the angular controller:
$scope.eventName = () => {
setTimeout(() => { alert('loaded!'); }, 0);
}
That makes the alert only pop up when everything about angular is loaded, that occur because of the call-stack of JavaScript that considers some codes as Microtasks and some others as Macrotasks and they have priorities like the Microtasks run always first and just after all Microtasks run, the Macrotasks can take the place on the call-stack.
And, setTimeout()
is considered a Macrotask for JavaScript, so it will only run as the latest tasks.
Here's a complete example that will catch all the ng-include
load events emitted by the application:
<html ng-app="myApp">
<head>
<script src="angular.min.js"></script>
</head>
<body ng-controller="myController">
<div ng-include="'snippet.html'"></div>
<script>
var myApp = angular.module("myApp",[]);
myApp.controller('myController', function($scope) {
$scope.$on('$includeContentLoaded', function(event, target){
console.log(event); //this $includeContentLoaded event object
console.log(target); //path to the included resource, 'snippet.html' in this case
});
});
</script>
</body>
</html>
A problem I had, and the reason I take the time to post this, is I failed to include both the ng-app
and ng-controller
in my HTML markup.
If I have to wait for the element to be present, I wrap a $timeout
with $includeContentLoaded
:
var selector = '#foo';
$rootScope.$on('$includeContentLoaded', function(event, templateName){
$timeout(() => {
const $el = angular.element(selector);
if ($el.length) {
// Do stuff with element.
}
});
});
The timeout gives it time load properly, specially if the ng-include
contains a directive that takes a few milliseconds to render.