Angular 4 Custom decorator - injecting services

2020-06-04 02:43发布

问题:

I want to create authentication decorator in my application.

Call should be simple as

@RequireAuthentication()
@HostListener('click', ['$event']) onClick(event: Event) {
....
}

As I know decorator can only be function, so in some other file I plan to have

export function RequireAuthentication() {
    if (!userService.isAuthenticated) {
        navigationService.goToLogin();
        return;
    }
}

Problem for me is how to properly initialize userService and navigationService in this case, since these services contains all logic for finding if user is authenticated and showing login screen.

I already tried:

  1. to use class with constructor for service initalization, but then nested method cannot be used as decorator
  2. to use Injectable class to create services, I need to create instance of this class, same problem.
  3. to use ModuleWithProviders approach to hide authentication implementation and only expose decorator, but not sure if that is right way to do this.

Any hints would be helpful. Could be that I miss something fundamental, since I'm not experienced angular developer or there is another way to approach this problem.

Thanks in advance!

回答1:

As explained in this answer, the solution that is idiomatic to the framework is to expose injector class instance property, so it could be accessed inside decorator. The existence of injector property can be also secured with an interface.

Since property decorator runs once and has access to class prototype but not instance, it's necessary to patch ngOnOnit method and retrieve all necessary services inside patched method with this.injector.get().

The alternative is to expose global injector to some object, as explained here. This is not idiomatic solution but a hack that will result in certain limitations and negative consequences. It can hardly be recommended for use in production.