Search code examples
angulardependency-injectionexternal

Angular 12 Dependency injection in external library


I need to inject a service into an external library for use it in a directive. this directive will be used in diferents apps and in diferents modules in each app. Each module will inject its own service.

Im creating an inyection token and a service interface in the module of the library, and importing its in the modules where are going to be used in the pricipal app.

then I provide the service using useExisting with this token, and in the directive use @Inject(INJECTION_TOKEN) in the constructor.

but i allways have this result when i load the componen where is used directive: "NullInjectorError: R3InjectorError(DashboardModule)[InjectionToken service token -> InjectionToken service token"

In my library module

import { Directive } from './directives/directive.directive';

@NgModule({
   exports: [
      ...,
      Directive
   ],
   imports: [CommonModule,...],
   declarations: [
      ...,
       Directive
   ]
})
export class LibraryModule {
  }

export const SERVICE_ADAPTER: InjectionToken<ServiceAdapter> =
  new InjectionToken('service token');

export interface ServiceAdapter {
  a(): void
}

In my library Directive:

import { Directive, ElementRef, EventEmitter, HostListener, Inject, Input, Output } from '@angular/core';
import { ServiceAdapter, SERVICE_ADAPTER } from '../library.module';

@Directive({
  selector: '[myDirective]'
})
export class Directive {
  @Input() field: string = ''
  @Input() method: string = ''
  

  constructor(private el: ElementRef, @Inject(SERVICE_ADAPTER) protected service: ServiceAdapter) {}

  @HostListener('keyup', ['$event'])
  keyup(event: any) {

        ...

  }


}

In the module where im going tu use it:

...
import { LibraryModule,SERVICE_ADAPTER } from 'Library...';

@NgModule({providers: [
      { provide: SERVICE_ADAPTER, useExisting: ProjectsService }
    ],
   declarations: [
     ...
   ],
   imports: [
      LibraryModule,
   ]
})
export class ProjectsModule {

}

Solution

  • When I understand you right, the link above is the solution for you. If you want for each lazy loaded module your custom / individual instance of service_adapter "forRoot - Concept" is your solution.

    You need a module for your directive in the library like:

    export interface IDirectiveModuleConfig {
        serviceAdapterConfiguration?: Provider;
    }
    
    
    @NgModule()
    export class YourDirectiveModule{
        public static forRoot(config: IDirectiveModuleConfig = {}): ModuleWithProviders<YourDirectiveModule> {
            return {
                ngModule: YourDirectiveModule,
                providers: [
                    config.serviceAdapterConfiguration
                ]
            };
        }
    }
    

    In your lazy loaded module you can specify how your service will be provided

    
    @NgModule(
    {
      imports: [
        YourDirectiveModule.forRoot({
           provide: ServiceAdapter,
           useClass: CustomImplementationServiceAdapter
       })
      ]
    }
    )
    export class LazyLoadedModule {
    }