26

Ok i have tons of $http() calls all around the app code,

i'm wondering is there any way / best practice to detect when all $http() around the app have finished ( success/error donesn't matter what they return, just need to know if finished )?

So that i can show a loading gif until they are loading ?

thanks

1

3 Answers 3

53

Do it like this:

angular.module('app').factory('httpInterceptor', ['$q', '$rootScope',
    function ($q, $rootScope) {
        var loadingCount = 0;

        return {
            request: function (config) {
                if(++loadingCount === 1) $rootScope.$broadcast('loading:progress');
                return config || $q.when(config);
            },

            response: function (response) {
                if(--loadingCount === 0) $rootScope.$broadcast('loading:finish');
                return response || $q.when(response);
            },

            responseError: function (response) {
                if(--loadingCount === 0) $rootScope.$broadcast('loading:finish');
                return $q.reject(response);
            }
        };
    }
]).config(['$httpProvider', function ($httpProvider) {
    $httpProvider.interceptors.push('httpInterceptor');
}]);

Then use event bound to $rootScope anywhere (preferable to use in directive):

$rootScope.$on('loading:progress', function (){
    // show loading gif
});

$rootScope.$on('loading:finish', function (){
    // hide loading gif
});
Sign up to request clarification or add additional context in comments.

7 Comments

great solution i'm wondering if actually i need or not to detect also directives http for example this will catch every http right?
i mean i dunno if to separate http() into blocking and unblocking ones for layout but this is my own problem
@sbaaaang It will catch all ajax request that are done angular way with $http. Of course if you use $.ajax (or any other xmlhttprequest) it will not catch
Great answer and it works. but for a learning purposes please do you mind explaining what happened in the code, Note: i have read about interceptors but i don't really understand what you were doing with loadingCount and config || $q.when(config); iread about interceptors from webdeveasy.com/interceptors-in-angularjs-and-useful-examples
this doesnt work (in angular 1.4 at least). loading:finish gets called for every single xhr request, not when they are all complete
|
10

It is possible if you execute all requests by $q.all

$scope.request1 = $http.get('request1URL', {cache: false});
$scope.request2 = $http.get('request2URL', {'cache': false});
$scope.loading = true;

$q.all([$scope.request1, $scope.request2]).then(function(values) {
     $scope.loading = false;
     // Do whatever you want
     // values[0], values[1]
});

Using ng-if, you can show and hide loading gif.

In case, if you use different $http call, then have a count or array in the $rootScope and update them whenever $http complete. Based on the count or array.length enable the loading gif.

2 Comments

thanks looking forward to what of the solutions i need actually
what if you want to globally do this and not have to implement $q.all logic in every single controller/service
0

Using answer by @karaxuna, I implement my solution like below. Plunker

<!doctype html>
<html ng-app="ui.bootstrap.demo">
  <head>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular-animate.js"></script>
    <script src="https://angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.14.3.js"></script>
    <script>
    var app = angular.module('ui.bootstrap.demo', ['ngAnimate', 'ui.bootstrap']);

    app.config(['$httpProvider', function ($httpProvider) {
        $httpProvider.interceptors.push(function ($q, $rootScope, $templateCache) {
            var AjaxLoadingCount = 0;
            return {
                request: function (config) {
                    console.log("[config.interceptorService] request config", config);                  
                    if (++AjaxLoadingCount === 1)
                    {
                        if (!$templateCache.get(config.url)) {
                            $rootScope.$broadcast('AjaxLoading:Progress');
                        }
                    }
                    return config || $q.when(config);
                },
                requestError: function (rejection) {
                    console.log("[config.interceptorService] requestError rejection", rejection);
                    if(--AjaxLoadingCount === 0) $rootScope.$broadcast('AjaxLoading:Finish');
                    return $q.reject(rejection);
                },
                response: function (response) {
                    console.log("[config.interceptorService] response response", response); 
                    if(--AjaxLoadingCount === 0) $rootScope.$broadcast('AjaxLoading:Finish');
                    return response || $q.when(response);                   
                },
                responseError: function (rejection) {
                    console.log("[config.interceptorService] responseError rejection", rejection);
                    if(--AjaxLoadingCount === 0) $rootScope.$broadcast('AjaxLoading:Finish');
                    return $q.reject(rejection);
                }
            };
        });
    }]);

    app.factory('ajaxFactory', function ($http) {

        var ajaxFactory = {};
        ajaxFactory.LoadData = function () {            
            return $http({
                method: "GET",
                url: "http://www.w3schools.com/angular/customers.php",
            });
        };
        return ajaxFactory;

    });

    app.controller('ModalDemoCtrl', function ($scope, ajaxFactory) {
        $scope.doAjax = function () {

            ajaxFactory.LoadData()
            .success(function (data, status, headers, config) {
                console.log("Data vai factory\n", JSON.stringify(data));
                console.log("Loading finish.");             
            }).error(function (data, status, headers, config) {

            });
        };
    });

    app.directive("ajaxLoadingDirective", function ($uibModal) {
        var modalInstance;
        return {
            restrict: 'EA', //E = element, A = attribute, C = class, M = comment            
            scope: true,
            link: function (scope, elem, attrs) {
                console.log("AjaxLoadingDirective.AjaxLoading:Progress");
                scope.$on("AjaxLoading:Progress", function () {                 
                    modalInstance = $uibModal.open({
                        animation: true,
                        templateUrl: 'myModalContent.html'
                    });
                });
                return scope.$on("AjaxLoading:Finish", function () {
                    console.log("AjaxLoadingDirective.AjaxLoading:Finish");
                    if(modalInstance === undefined) return;
                    modalInstance.dismiss();
                });
            }
        }
    });

    </script>
    <link href="https://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet">
  </head>
  <body>
    <div ng-controller="ModalDemoCtrl">
        <script type="text/ng-template" id="myModalContent.html">
            Loading data .......................            
        </script>
        <button type="button" class="btn btn-default" ng-click="doAjax()">Execute Ajax</button>
        <div ajax-loading-directive ></div>
    </div>
  </body>
</html>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.