1

I use ngx-toastr library for showing notifications.This library contains ToastrService. But, I want to create my own wrapper for this service, because I need different configs for different types of messages. So I have:

@Injectable()
export class NotificationService {
  constructor(private toastrService: ToastrService) {
  }

  public success(message: string, title?: string): void {
    this.toastrService.success(message, title);
  }

  public error(message: string, title?: string): void {
    let toastConfig = {
      ...
    };
    this.toastrService.error(message, title, toastConfig);
  }

  public info(message: string, title?: string): void {
    let toastConfig = {
      ...
    };
    this.toastrService.info(message, title, toastConfig);
  }

  public warning(message: string, title?: string): void {
    this.toastrService.warning(message, title);
  }
}

I want to prevent other developers from injecting ToastrService somewhere. If user inject ToastrService to component or other service except of NotificationService I want to throw error. How can I do this?

Module:

@NgModule({
  imports: [
    ToastrModule.forRoot(),
  ],
  declarations: [],
  providers: [    
    NotificationService
  ],
  exports: []
})
user348173
  • 8,818
  • 18
  • 66
  • 102

1 Answers1

1

If user inject ToastrService to component or other service except of NotificationService I want to throw error.

You don't need to do that. Let them all consume the service by the usual token ToastrService but they will get the instance of your decorated NotificationService

This library declares ToastrService on the module level. You can redefine this service on the root component level under the same token:

@Component({
   providers: [
      { provide: ToastrService, useClass: NotificationService} 
})
export class AppRootComponent {}

When any component that is a child of the root app component requests that service it will get the decorated version of the service.

If you still want to throw an error (although I believe this is not how decorating is done), you can do like this:

class ToastrServiceThatThrows { 
    constructor() { throw new Error('I should not be instantiated') } 
}

@Component({
   providers: [
      { NotificationService  },
      { provide: ToastrService, useClass: ToastrServiceThatThrows }  
})
export class AppRootComponent {}

But you have to use @SkipSelf() decorator on the NotificationService:

@Injectable()
export class NotificationService {
  constructor(@SkipSelf() private toastrService: ToastrService) {  }

So that you get real class instance from the module injector. And don't register NotificationService on the module, just on the root component.

Max Koretskyi
  • 101,079
  • 60
  • 333
  • 488
  • This is not what I actually want. One developer could inject ToastrService, another developer could NotificationService.... yes, the NotificationService will be injected in both cases.... but in the code it will look like two different services. That's why I want to throw error explicitly, when developer uses ToastrService – user348173 Jul 28 '17 at 07:26
  • Now, I get exception ```No provider for ToastrService!``` – user348173 Jul 28 '17 at 07:40
  • can you setup a minimal plunker with my suggestion? I'll take a look – Max Koretskyi Jul 28 '17 at 07:44
  • ok, make sure you don't register `NotificationService` on the module, just on the root component – Max Koretskyi Jul 28 '17 at 07:45
  • if I remove```NotificationService``` from module, then ```No provider for NotificationService!``` – user348173 Jul 28 '17 at 07:49
  • create a plunker, I'll take a look – Max Koretskyi Jul 28 '17 at 07:51
  • Tested in plunker... and works fine...One more question, is it possible to do the same, but without touching app root component, may be with modules. I have Core module which I import to AppModule. This is plunker https://plnkr.co/edit/Dw45pR3qDmK7wEPXw9Gj?p=preview – user348173 Jul 28 '17 at 08:13
  • @user348173, unfortunately not, it's not possible, because all module providers are merged and only one injector is created. Read [this answer](https://stackoverflow.com/a/45242774/2545680). Only lazy loaded modules create their own injectors. Please, consider accepting or upvoting my answer if it helped. Thanks – Max Koretskyi Jul 28 '17 at 08:17
  • Yes, your asnwer was helpfull. Thank you. – user348173 Jul 28 '17 at 08:20