Alternative To Angular.element(document).ready
Solution 1:
Generally Angular application is already bootstrapped on document ready
. This is default behaviour for automatic bootstrapping with ng-app
, and manual bootstrapping with angular.bootstrap
should be performed on ready
as well.
The question is specific to current case (Microsoft's Bing Maps API). Considering that ready
is suggested by Microsoft, a developer is on his/her own with better alternatives.
<scriptsrc="https://www.bing.com/api/maps/mapcontrol"></script>
is loaded synchonously, but it triggers a number of dependencies to load which aren't loaded yet at the moment when initial document ready
is triggered. Actually, it requires ready
inside another ready
in order to complete the initialization, this is exactly what the original code and Microsoft example show, and it doesn't look very good.
In order to avoid race conditions application bootstrap can be postponed to the moment when all prerequisites will be loaded, i.e. window load
event instead of document ready
. It may provide considerable delay but it guarantees that scripts that the application relies on were loaded, regardless of how their transport is performed:
angular.element(window).on('load', () => {
angular.bootstrap(document.body, ['app']
});
The alternative that API provides to control initialization process is global callback function:
<scriptsrc="https://www.bing.com/api/maps/mapcontrol?callback=globalCallbackName"></script>
A callback can be packed with a service instead of relying on <script>
:
angular.module('bingMaps', [])
.factory('bingMapsLoader', ($q, $window, $document, $timeout) => {
var script = document.createElement('script');
script.src = 'https://www.bing.com/api/maps/mapcontrol?callback=bingMapsCallback';
script.async = true;
$document.find('body').append(script);
return$q((resolve, reject) => {
$window.bingMapsCallback = resolve;
$timeout(reject, 30000);
});
});
bingMapsLoader
promise can be chained to guarantee that API was initialized, put into router resolver, etc.
Additionally, controller constructor is executed before directive is being compiled. Whether third-party APIs are used or not, it is correct to move all DOM-specific code to pre/post link function in Angular 1.4 and lower and to controller $onInit
or $postLink
hook in Angular 1.5 or higher:
app.controller('FooController', function (bingMapsLoader) {
this.$postLink = () => {
bingMapsLoader.then(() =>this.mapsInit());
};
this.mapsInit = () => {
Microsoft.Maps.Map(...);
};
...
Post a Comment for "Alternative To Angular.element(document).ready"