As your AngularJS applications get bigger, you may start to notice that the apps don't bootstrap immediately - it takes time to load all the scripts over the network. Out of the box, AngularJS deals with this by providing an ngCloak directive which will hide pre-compiled HTML. But that's kind of a weak solution. Instead, it would be nicer to present the user with a meaningful "loading" screen that gets removed when the scripts have loaded and the AngularJS application has been fully bootstrapped.
Until your AngularJS application has been bootstrapped, all the HTML in your browser is just normal "static" HTML. This isn't a weakness, though, it's a strength. As web developers, static HTML is our bread-and-butter. Of all the things that we do on a daily basis, static HTML is the easiest to deal with and the easiest to reason about.
Getting a loading page to show is simple - we just need to slap some HTML on the page. Getting the loading page to disappear once the AngularJS application is bootstrapped, that's the point of complexity.
The easiest way to do this is to simply wrap some static HTML in an ngIf directive that is set to false:
<!-- BEGIN: Pre-Bootstrap Loading Screen. --> <div ng-if="false"> <p> This will show until the application is bootstrapped. Then, the ngIf directive will immediately rip it out of the page. </p> </div> <!-- END: Pre-Bootstrap Loading Screen. -->
This will show the HTML, by default (that's what browsers do); then, once AngularJS compiles and links the HTML, the ngIf directive will remove the given DOM element.
While this approach is very simple, it does have few drawbacks. For one, the ngIf directive binds a $watch() handler which will live for the duration of the application. Granted, it doesn't do any computation, so it has no practical cost; but, it just feels less than clean. And, another drawback is that it's hard to get animations to work during the bootstrapping phase of the application.
To get around these two drawbacks, I'm going to create a custom directive that bypasses any $watch() bindings and elegantly animates the pre-loading screen out of view using the ngAnimate module (and $animate service).
This it the first time that I've ever used $animate and I, of course, immediately ran into an issue. When the AngularJS application is bootstrapping, all animations are disabled. They remain disabled until all routing and templating information is loaded and at least two digests have passed. This is intended to prevent a flurry of animation when the application loads.
But, I want the animation to run immediately, regardless of the state of the application. Luckily, you can override this by using the ngAnimateChildren directive. This directive is intended to allow you to animate a child element even while the parent containers are animating. But, an ?? undocumented ?? side-effect of this is that it will also allow you to animate children while animations are disabled at the root (such as they are during bootstrapping).
Bringing this all together, my directive will execute the .leave() animation on its child container; then, once the animation is complete, the directive will completely remove all elements from the page. And, since it doesn't create a new scope or define any new $watch() bindings, it leaves the main AngularJS application quite clean.
As a sort of hack, I'm putting the minimum viable Style block inside the loading screen directive container. This way, when I strip out the container, the Style block will be stripped out as well.
This is the first time that I've used the $animate service; it seems pretty cool! Normally, I would have just used jQuery to .fadeOut() the container; but, I'm trying to be more adventurous in what responsibilities I give to AngularJS. That said, regardless of the animation mechanism, this is a pretty easy way to create a pre-bootstrap loading screen in your AngularJS application.
Want to use code from this post? Check out the license.