Friday, February 20, 2015

javascript - How to make a loading indicator for every asynchronous action (using $q) in an angularjs-app - Stack Overflow

javascript - How to make a loading indicator for every asynchronous action (using $q) in an angularjs-app - Stack Overflow



Although I find it very complicated, unnecessary and probably broken, you could decorate $qand override its defer function.
Every time someone asks for a new defer() it runs your own version which also increments a counter. Before handing out the defer object, you register a finally callback (Angular 1.2.0 only but always may fit, too) to decrement the counter.
Finally, you add a watch to $rootScope to monitor when this counter is greater than 0 (faster than having pendingPromisses in $rootScope and bind like ng-show="pendingPromisses > 0").
app.config(function($provide) {
    $provide.decorator('$q', ['$delegate', '$rootScope', function($delegate, $rootScope) {
      var pendingPromisses = 0;
      $rootScope.$watch(
        function() { return pendingPromisses > 0; }, 
        function(loading) { $rootScope.loading = loading; }
      );
      var $q = $delegate;
      var origDefer = $q.defer;
      $q.defer = function() {
        var defer = origDefer();
        pendingPromisses++;
        defer.promise.finally(function() {
          pendingPromisses--;
        });
        return defer;
      };
      return $q;
    }]);
});
Then, view bound to a scope that inherits from $rootScope can have:
<span ng-show="loading">Loading, please wait</span>
(this won't work in directives with isolate scopes)
See it live here.

No comments: