Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Set rootScope variable on httpIntercept

Tags:

angularjs

I'd like to be able to set up an AngularJS http interceptor which will set $rootScope.loading to true or false, depending on whether an AJAX request is currently ongoing.

So far I've put the following together:

angular.module('myApp')
.config(function ($httpProvider) {
  $httpProvider.responseInterceptors.push('loadingInterceptor');

  var loadingFunction = function (data, headersGetter) {
      $rootScope.loading = true

      return data;
  };
  $httpProvider.defaults.transformRequest.push(loadingFunction);
})
.factory('loadingInterceptor', function ($q, $window, $rootScope) {
    return function (promise) {
        return promise.then(function (response) {
            $rootScope.loading = false;
            return response;

        }, function (response) {
            $rootScope.loading = false;
            return $q.reject(response);
        });
    };
});

But I'm unable to inject $rootScope into the config block, so I have no way of setting the $rootScope.loading variable when an HTTP request begins.

Am I missing something here? How should I do this?

like image 573
JP. Avatar asked Apr 30 '13 15:04

JP.


2 Answers

responseInterceptors has been deprecated http://docs.angularjs.org/api/ng.$http. I have enhanced the previous example:

app.factory('myHttpInterceptor', ['$q', '$rootScope', '$injector',
    function ($q, $rootScope, $injector) {
        $rootScope.showSpinner = false;
        $rootScope.http = null;
        return {
            'request': function (config) {
                $rootScope.showSpinner = true;
                return config || $q.when(config);
            },
            'requestError': function (rejection) {
                $rootScope.http = $rootScope.http || $injector.get('$http');
                if ($rootScope.http.pendingRequests.length < 1) {
                    $rootScope.showSpinner = false;
                }
                if (canRecover(rejection)) {
                    return responseOrNewPromise
                }
                return $q.reject(rejection);
            },
            'response': function (response) {
                $rootScope.http = $rootScope.http || $injector.get('$http');
                if ($rootScope.http.pendingRequests.length < 1) {
                    $rootScope.showSpinner = false;
                }
                return response || $q.when(response);
            },
            'responseError': function (rejection) {
                $rootScope.http = $rootScope.http || $injector.get('$http');
                if ($rootScope.http.pendingRequests.length < 1) {
                    $rootScope.showSpinner = false;
                }
                if (canRecover(rejection)) {
                    return responseOrNewPromise
                }
                return $q.reject(rejection);
            }
        }
    }
]);

And you can use the factory like so:

app.config(function ($httpProvider) {
    $httpProvider.interceptors.push('myHttpInterceptor');
});
like image 167
Tshepo Mgaga Avatar answered Oct 30 '22 01:10

Tshepo Mgaga


You can only insert providers in module.config, but you shouldn't do this in the default transformers anyway, you should do it in the interceptors (like you do when you're setting loading = false).

There might be more than one request going on at the same time. Something like this might work:

angular.module('myApp')
  .config(function ($httpProvider) {
    $httpProvider.responseInterceptors.push(function ($rootScope) {
      $rootScope.numLoadings = 0;
      $rootScope.loading = false;
      return function (promise) {
        $rootScope.numLoadings++;
        $rootScope.loading = true;
        // make sure the loading screen is visible
        var hide = function (r) {
          if ((--$rootScope.numLoadings)===0){
            //console.log('hide the loading screen');
            $rootScope.loading = false;
          }
          return r;
        };
        return promise.then(hide, hide);
      };
    });
  });

Ofcourse you don't have to put numLoadings in the root scope, I just put it there for this example: http://plnkr.co/edit/32Mh9UOS3Z4vnOtrH9aR?p=preview

like image 22
joakimbl Avatar answered Oct 30 '22 02:10

joakimbl