Search code examples
javascriptangularjsangular-http-interceptors

AngularJS: how to stay in 'run' method until it finishes


I have a simple scenario - I wish to init my http calls with interceptor that will add a value in headers (a token of some kind).

The problem is that the token is received via http as well (it should be the first call) but I don't know how to make all other calls to wait for it to finish before issuing their own calls...

.factory('sessionData', function () {
    var currentToken = '[uninitialized-token]';
    return {
        getToken: function () {
            return currentToken;
        },
        setAuthData: function (token) {
            currentToken = token;
        }
    }
})
.factory('sessionInjector', ['sessionData', function (sessionData) {
    var sessionInjector = {
        request: function (config) {
            console.log("sending with token: " + sessionData.getToken());
            config.headers['x-header-sessionID'] = sessionData.getToken();
        }
    };
    return sessionInjector;
}])

.config(['$httpProvider', function ($httpProvider) {
    $httpProvider.interceptors.push('sessionInjector');
}])

.run(['$http', 'configs', 'sessionData', function ($http, configs, sessionData) {
    $http.get(configs.authApiUrl + 'login').then(function (ret) {
        sessionData.setAuthData(ret);
        console.log("successfully authenticated with token " + sessionData.getToken());
    });
}])

.controller('TestCtrl', function($http){
    $scope.p1 = 'Uninitialized';

    $http.get('http://localhost/api/getData').then(function(ret){
        $scope.p1 = ret;
    });
});

The problem is that the TestCtrl issues an http call before the run method finished getting the token (resulting in header value having the [uninitialized-token] in it's value).

How to make the controllers wait for the 'run' async methods to finish?


Solution

  • $http interceptors can be used to return promises in their callbacks. You can use this to intercept each call and delay it until the promise is resolved.

    You should understand how promises work for this.

    Example:

    myModule.factory('tokenPromise', function($http) {
        return $http.get({url: 'myurl/token', bypassToken: true}).then(function(data) {
             // This is when your token webservice return, deal with the response here
             return data.token;
        });
    });
    
    myModule.factory('myHttpInterceptor', function($q, tokenPromise) {
      return {
        'request': function(config) {
          if (config.bypassToken) return config;
             // This ensures the token promise is resolved before proceeding with the request.
          return tokenPromise.then(function(token) {
             config.headers['x-header-sessionID'] = token;
             return config;
          });
        },
      };
    });
    
    
    myModule.config(function($httpProvider) {
         //wire the interceptor here
         $httpProvider.interceptors.push('myHttpInterceptor');
    })
    

    reference: http service on angular official docs