angularjs http interceptor class (ES6) loses binding to 'this'

后端 未结 9 1630
轮回少年
轮回少年 2021-02-05 11:14

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

9条回答
  •  再見小時候
    2021-02-05 12:07

    The context (this) is lost because the Angular framework only keeps references to the handler functions themselves, and invokes them directly without any context, as alexpods has pointed out.

    I recently wrote a blog post about writing $http interceptors using TypeScript, which also applies to ES6 classes: AngularJS 1.x Interceptors Using TypeScript.

    To summarise what I have discussed in this post, in order to not lose this in your handlers, you'll have to define the methods as arrow functions, effectively putting the functions directly inside of the class's constructor function in the compiled ES5 code.

    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);
        }
    }
    

    If you really insist on having your interceptor written as a fully prototype-based class, you could define a base class for your interceptor and extend it. The base class would replace the prototype interceptor functions with instance methods, so we can write our interceptors like this:

    class HttpInterceptor {
      constructor() {
        ['request', 'requestError', 'response', 'responseError']
            .forEach((method) => {
              if(this[method]) {
                this[method] = this[method].bind(this);
              }
            });
      }
    }
    
    class AuthenticationInterceptor extends HttpInterceptor {
    
        /* ngInject */
        constructor($q, $window) {
            super();
            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);
        }
    }
    

提交回复
热议问题