When an IONIC application starts becoming complex it involves a lot of asynchronous operation at startup, like doing $http requests or reading cached data from localStorage and also some kind of plugins iteration.
To be sure that everything is ready before it can be used, we needs to wait that Cordova emits the deviceready event. Luckily Ionic has a wrapper for it called $ionicPlatform.ready() that fires a callback when this event has happens or it has already been added. So we just can use it everywhere in our code, especially inside services.
But which is a good way to organize the application at boot? This is my personal approach to have reusable components to be used when my IONIC app bootstraps.
step 1: splash screen
First i configure the default page to be a splash screen in “.config()” with: $urlRouterProvider.otherwise('/app/splash');
This state has no controller just a template called splash.html
Its shared across all my applications, it just display the splash screen as background using CSS.
It has a spinner, a progress bar, and an area for messages that at this point are hidden using “ng-if“.
Ionic usually load this at the start and it will be very fast, and also avoid me to use the Cordova’s splash screen plugin.
step 2: waiting for the the ready event
Before the APP can use any plugin or services it needs to wait for “deviceready“.
So in “.run” i use this code:
$ionicPlatform.ready(function () { $ionicHistory.nextViewOptions({ disableAnimate: true, disableBack: true }); $state.go('app.loading', {}, {reload:true}); });
This just go the state “app.loading” that has the same template “splash.html” from the previous step but with “loadingCtrl” as controller.
I tweaked the $ionicHistory object to skip the animations (because i keeped the same template) and to hide the back button from the top bar.
step 3: loading
In “loadingCtrl” i’ve my main initialization code wrapped by a few Ionic services calls. This is where i initialize all my services. I use $scope variables to communicate with the splash’s template about the progress of the loading phase.
$scope.$on('$ionicView.beforeEnter', function(){ //This is fired twice in a row $ionicHistory.clearCache().then(function(){ $ionicHistory.clearHistory(); $ionicHistory.nextViewOptions({ disableAnimate: true, disableBack: true, historyRoot: true }); myService.myInitializationCode().finally(function(){ $state.go('app.index', {}, {reload:true}); }); });
You can notice that, first, i use the “beforeEnter” event in such a way that, when i wish to restart or reload all the data in my application, i just simple issue: $state.go('app.loading');
instead of other fancy methods.
For the same reason i clear the view’s cache and the history’s cache; those operations has been proved very useful when the application needs to be reloaded in order to use a different language with ngTranslate. If you don’t do so you’ll still get the old views translated with the old language.
To the history service i also added the historyRoot settings in order to make the next page the root of my navigation stack, indeed, once all my initialization code is completed, i finally can go to the state “app.index” that is the “real” homepage of my application.
final step: homepage
Finally “app.index” is the state with the homepage, at this point all my services will be initialized already by the “app.loading” state and all the data (remote or cached) are available and ready to use.
That’s it.