Angularjs Loading Screen On Ajax Request


Answer :

Instead of setting up a scope variable to indicate data loading status, it is better to have a directive does everything for you:

angular.module('directive.loading', [])      .directive('loading',   ['$http' ,function ($http)     {         return {             restrict: 'A',             link: function (scope, elm, attrs)             {                 scope.isLoading = function () {                     return $http.pendingRequests.length > 0;                 };                  scope.$watch(scope.isLoading, function (v)                 {                     if(v){                         elm.show();                     }else{                         elm.hide();                     }                 });             }         };      }]); 

With this directive, all you need to do is to give any loading animation element an 'loading' attribute:

<div class="loading-spiner-holder" data-loading ><div class="loading-spiner"><img src="..." /></div></div> 

You can have multiple loading spinners on the page. where and how to layout those spinners is up to you and directive will simply turn it on/off for you automatically.


Here's an example. It uses the simple ng-show method with a bool.

HTML

<div ng-show="loading" class="loading"><img src="...">LOADING...</div> <div ng-repeat="car in cars">   <li>{{car.name}}</li> </div> <button ng-click="clickMe()" class="btn btn-primary">CLICK ME</button> 

ANGULARJS

  $scope.clickMe = function() {     $scope.loading = true;     $http.get('test.json')       .success(function(data) {         $scope.cars = data[0].cars;         $scope.loading = false;     });   } 

Of course you can move the loading box html code into a directive, then use watchonwatch on scope.loading. In which case:

HTML:

<loading></loading> 

ANGULARJS DIRECTIVE:

  .directive('loading', function () {       return {         restrict: 'E',         replace:true,         template: '<div class="loading"><img src="..."/>LOADING...</div>',         link: function (scope, element, attr) {               scope.$watch('loading', function (val) {                   if (val)                       $(element).show();                   else                       $(element).hide();               });         }       }   }) 

PLUNK: http://plnkr.co/edit/AI1z21?p=preview


I use ngProgress for this.

Add 'ngProgress' to your dependencies once you've included the script/css files in your HTML. Once you do that you can set up something like this, which will trigger when a route change was detected.

angular.module('app').run(function($rootScope, ngProgress) {   $rootScope.$on('$routeChangeStart', function(ev,data) {     ngProgress.start();   });   $rootScope.$on('$routeChangeSuccess', function(ev,data) {     ngProgress.complete();   }); }); 

For AJAX requests you can do something like this:

$scope.getLatest = function () {     ngProgress.start();      $http.get('/latest-goodies')          .success(function(data,status) {              $scope.latest = data;              ngProgress.complete();          })          .error(function(data,status) {              ngProgress.complete();          }); }; 

Just remember to add 'ngProgress' to the controllers dependencies before doing so. And if you are doing multiple AJAX requests use an incremental variable in the main app scope to keep track when your AJAX requests have finished before calling 'ngProgress.complete();'.


Comments

Popular posts from this blog

Are Regular VACUUM ANALYZE Still Recommended Under 9.1?

Can Feynman Diagrams Be Used To Represent Any Perturbation Theory?