I am building and AngularJS app using ES6 classes with traceur transpiling to ES5 in AMD format.
in my module I import the interceptor class and register it as a service, and then register this service with the $httpProvider.interceptors in module.config:
var commonModule = angular.module(moduleName, [constants.name]);
import authenticationInterceptor from './authentication/authentication.interceptor';
commonModule.service('authenticationInterceptor', authenticationInterceptor);
commonModule.config( $httpProvider => {
$httpProvider.interceptors.push('authenticationInterceptor');
});
My interceptor class injects both $q and the $window services, saves them in the constructor for later use. I followed this part with the debugger and the injection is happening properly:
'use strict';
/*jshint esnext: true */
var authenticationInterceptor = class AuthenticationInterceptor {
/* ngInject */
constructor($q, $window) {
this.$q = $q;
this.$window = $window;
}
responseError(rejection) {
var authToken = rejection.config.headers.Authorization;
if (rejection.status === 401 && !authToken) {
let authentication_url = rejection.data.errors[0].data.authenticationUrl;
this.$window.location.replace(authentication_url);
return this.$q.defer(rejection);
}
return this.$q.reject(rejections);
}
}
authenticationInterceptor.$inject = ['$q', '$window'];
export default authenticationInterceptor;
When I make a request that responds with a 401 the interceptor triggers appropriately, but in the 'responseError' method the 'this' variable points to the window object and not to my interceptor, hence I do not have access to this.$q or this.$window.
I cannot figure out why? Any ideas?
Note that using arrow functions in class properties is an experimental feature for ES7. However most transpilers don't have a problem with it.
If you want to stick to the official ES6 implementation you can create instance methods instead of prototype methods by defining your methods in the constructor.
I like this solution because it decreases the amount of boilerplate code;
this
. So instead of usingthis.$q
you can just use$q
.Having one extra level of indentation is a downside. Furthermore this method might not be suitable for classes that are instantiated a lot as it consumes more memory in that case. E.g.; Using direct class properties (transpiled to prototype methods) is more efficient for controllers of components that are likely to be used multiple times on one page. Don't worry about services, providers and factories as these are all singletons and they will only be instantiated once.
This is exactly the same problem I'm experiencing, however, I found a workaround by setting the 'this' in a self variable just like solving the scoping issue on es5, and it works fine:
To add to the conversation, you could return an object from the constructor that contains explicitly bound class methods.
My working solution without using ngInject
myInterceptor.js
}
myAngularApp.js
Working solution with arrow functions: