Create loading spinner dialog while route changes using angularjs

When a route change happens, it might so happen that the new template being loaded takes time to show up final template. So, while the template processing is happening, we can show a loading spinner to avoid blank screen or screen stalls while transitioning from one route to another.

Overview

To do this, we hook into the route change events. The events captured are:
  • $stateChangeStart
  • $viewContentLoaded
When the route change starts, we show the loading spinner using $stateChangeStart event. And this is ended when the $viewContentLoaded event occurs.

Demo

Code

HTML

<!DOCTYPE html>
<html>

<head>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.6.3/css/font-awesome.min.css">
  <link rel="stylesheet" href="style.css">
  <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0/angular.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.3.1/angular-ui-router.min.js"></script>
  <script src="script.js"></script>
  <script type="text/ng-template" id="template1.html">
    <div>
      <div>Content of the template 1</div>
      <a ui-sref="template2">Load template 2</a>
      <fullscreen-dialog ng-show="isVisible.loading">
        <div class="dialog">
          <div class="content">
            <i class="fa fa-cog fa-spin fa-3x fa-fw"></i>
          </div>
        </div>
      </fullscreen-dialog>
    </div>
  </script>
  <script type="text/ng-template" id="template1.html">
    <div>
      <div>Content of the template 2.</div>
      <a ui-sref="template1">Load template 1</a>
      <fullscreen-dialog ng-show="isVisible.loading">
        <div class="dialog">
          <div class="content">
            <i class="fa fa-cog fa-spin fa-3x fa-fw"></i>
          </div>
        </div>
      </fullscreen-dialog>
    </div>
  </script>
</head>

<body id="dialog" ng-app="loadingDialogApp" ng-controller="mainController">
  <ui-view></ui-view>
</body>

</html>

SCRIPT

angular.module('loadingDialogApp', ['ui.router']).
run(function($rootScope, $timeout) {
  $rootScope.isVisible = {
    loading: false
  };
  $rootScope.$on("$stateChangeStart", function() {
    $rootScope.isVisible.loading = true;
        //alert($rootScope.isVisible.loading)
      });
  $rootScope.$on("$viewContentLoaded", function () {
    $timeout(function () {
      $rootScope.isVisible.loading = false;
            //alert($rootScope.isVisible.loading)
          }, 2000);
  });
}).
config(function($stateProvider, $urlRouterProvider) {
  $urlRouterProvider.otherwise('/template1');
  $stateProvider.
  state('template1', {
    url: '/template1',
    templateUrl: 'template1.html'
  }).
  state('template2', {
    url: '/template2',
    templateUrl: 'template2.html'
  })      
}).
controller('mainController', function ($scope) {
  
}).
directive('fullscreenDialog', function () {
  return {
    controller: 'fsDialogController',
    link: fsDialogLinker,
    restrict : 'E',
    replace: true,
    transclude: true,
    template : '
' } function fsDialogLinker(scope, element, attribute) { scope.$on('$destroy', function () { var bodyElement = document.getElementById("dialog"); bodyElement.classList.remove('noscroll'); }); } }). controller('fsDialogController', function ($scope) { $scope.isPanelVisible = false; var bodyElement = document.getElementById("dialog"); $scope.showDialog = function () { $scope.isPanelVisible = true; bodyElement.classList.add('noscroll'); }; $scope.hideDialog = function () { $scope.isPanelVisible = false; bodyElement.classList.remove('noscroll'); }; });

STYLESHEET

.noscroll {
  overflow: hidden;
}
.dialog {
  z-index: 999999;
  position: fixed;
  left: 0;
  top: 0;
  width: 100%;
  min-height: calc(100%);
  height: auto!important;
  background: #efeae1;
}
.dialog[ng-cloak] {
  display: none;
}
.dialog .content {
  position: absolute;
  width: 100%;
  top: 50%;
  text-align: center;
  transform: translateY(-50%);
}
.fa-cog {
  font-size: 3em;
}
Do share your feedback and suggestions.