Search code examples
angulartypescriptecmascript-6decorator

Can decorators call services in angular?


I've started having a look on decorators for typescript. Angular implements a lot of decorators (Components, Injectables, Directives, etc). I have a recurrent piece of logic that verifies if the user has logged in, and if he is authorized to execute a given function. Here is an example of it:

@Component()
class MyClass {
    someMethod() {
         if(this.authService.isLogged() && this.authService.isAuth(...)) { 
             // logic
         }
    }
}

This works as planned, but becomes really bothersome to read the code, also non-intuitive for my coworkers. What I intended to do was to make a decorator that would first verify is a user is logged, then if that user meets the requirements, if he passes on both, the function would execute, if not, it would ignore the execution and return a default value. This is what I tried and came up with for the login verification function:

export function isLogged() {
    return (target, key, descriptor) {
        const original = descriptor.value;
        descriptor.value = function (...args: any[]) {
            // <- add login verification here
            return original.apply(this, args);
        };
        return descriptor;
    }
}

The problem I'm facing is how I can call the function's context services to verify if he is logged in without passing explicitly the 'this' keyword? For more clarity this is the usage I'm trying to achieve

@Component()
class MyClass {
    @isAuth(...) // <- here without passing 'this'
    @isLogged()
    someMethod() {
        // logic
    }
}

I need to emphasize that this decorator needs to defer the verification logic to an authorization service, as it has the user login, authorities and other relevant information for the decorator. One solution of what I'm asking is a way to inject services to given functions. Taking my example decorator, it has a comment denoting the missing part where a call to the authorization would be. I suppose there is a way to inject and call a service in a function, but didn't find any solutions online.


Solution

  • As per comments in my question it was noted the this keyword does have the full context of the class, including services placed at its constructor. So I can make modify my decorator to access the service:

    export function isLogged() {
        return (target, key, descriptor) {
            const original = descriptor.value;
            descriptor.value = function (...args: any[]) {
                if (this.authorizationService.isLogged()) {
                    return original.apply(this, args);
                } else {
                    return () => {};
                }
            };
            return descriptor;
        }
    }