Reputation: 865
I am trying to send extra header in XHR request (init with $resource).Following is my config
var app = angular.module('app',['angularMoment']).
run(function ($rootScope,$location,$route, $timeout, $http) {
var token = localStorage.getItem("userToken");
$http.defaults.headers.common.token = token;
}
I am changing hash params (eg. after login process) to navigate in app. So when I am sending any XHR request after login process (wihout mannual reload), it's sending token (request header) as NULL. But when I reload my page manually it's working fine (i.e sending token as header). Also I tried with $route.reload()
but it's not working.
Please suggest how can I get rid of this issue.
Thanks
EDIT :
After trying with follwing code :
app.factory('tokenInterceptorService', ['$q', '$location', function ($q, $location) {
var tokenInterceptor = {};
var request = function (config) {
config.headers = config.headers || {};
var token = localStorage.getItem("userToken");
config.headers.token = token;
return config;
}
// if response errors with 401 redirect to lgoin
var response = function (rejection) {
if (rejection.status === 401) {
$location.path('/');
}
return $q.reject(rejection);
}
tokenInterceptor.request = request;
tokenInterceptor.response = response;
return tokenInterceptor;
}]);
app.config(function ($httpProvider) {
$httpProvider.interceptors.push('tokenInterceptorService');
});
app.run(function ($rootScope, $location,$route, $timeout, $http) {
$rootScope.config = {};
$rootScope.config.app_url = $location.url();
$rootScope.config.app_path = $location.path();
$rootScope.layout = {};
$rootScope.layout.loading = false;
$rootScope.$on('$routeChangeStart', function () {
//need to validate
console.log($rootScope.isValidated + "app");
//show loading
$timeout(function(){
$rootScope.layout.loading = true;
});
});
$rootScope.$on('$routeChangeSuccess', function () {
//hide loading
$timeout(function(){
$rootScope.layout.loading = false;
}, 200);
});
$rootScope.$on('$routeChangeError', function () {
alert('Something went wrong. Please refresh.');
$rootScope.layout.loading = false;
});
})
It stop rendring the views in application with ".run" and trapping in $rootScope.$on('$routeChangeError',
and giving the error Error: [$rootScope:inprog] $digest already in progress.
Upvotes: 3
Views: 874
Reputation: 1941
Since if I understand correctly your user token is always taken from localstorage, you can setup a watch on that localStorage key in your run function (Demo plunker for working with Localstorage in angular: http://plnkr.co/edit/7hP13JAjPybxkRuMZLZ0?p=preview )
angular.module('app',[]).run(['$rootScope', '$http', function($root, $http) {
$root.$watch(function() {
return localStorage.getItem('userToken');
}, function(userToken) {
$http.defaults.headers.common.token = userToken;
});
});
This should solve your problems without any interceptors etc.
However I'd actually recommend using http interceptor as calls to localStorage are slow, or setting the defaults where you actually set the user token after login or logout (save it also on a scope variable, and initialize it in the run part like you do now).
Upvotes: 2
Reputation: 2664
module.run
executes well before anything else in the app (but after module.config
). Would the localStorage
have been set by then? I think that is happening later, which is why you see this value after reloading the page.
An interceptor would be the way to go.
How are you setting the value in localStorage
?
Upvotes: 2
Reputation: 3830
You need to set up an interceptor that alters every request sent to the server. You can find out more form the docs here, but essentially you need to set up a factory service on your app to add the token header like so:
app.factory('tokenInterceptorService', ['$q', '$location', 'localStorage', function ($q, $location, localStorage) {
var tokenInterceptor = {};
var request = function (config) {
config.headers = config.headers || {};
var token = localStorage.getItem("userToken");
if (token) {
config.headers.token = token;
}
return config;
}
// if response errors with 401 redirect to lgoin
var response = function (rejection) {
if (rejection.status === 401) {
$location.path('/login');
}
return $q.reject(rejection);
}
tokenInterceptor.request = request;
tokenInterceptor.response = response;
return tokenInterceptor;
}]);
and then register it during the config stage with:
app.config(function ($httpProvider) {
$httpProvider.interceptors.push('tokenInterceptorService');
});
Upvotes: 2