maximz101
maximz101

Reputation: 678

Pass Implementation to Angular Module When importing it

If I have an Angular Module A that depends on a certain service S. But instead of implementing the service directly, I want to deal with an interface I and let the consumer of A pass the actual implementation when importing it. The implementation will be an Angular service decorated with @Injectable and has its own dependencies.

Is that feasible in Angular? if yes, what are the steps to implement it?

Upvotes: 3

Views: 848

Answers (2)

Jota.Toledo
Jota.Toledo

Reputation: 28434

To archive this, you could use abstract classes instead of interfaces to make the implementations exchangeable:

app/
├── foo.service.ts
├── foo/
│   ├── abstract-foo.provider.ts
│   ├── foo.module.ts
│   ├── foo.component.ts
├── app.module.ts

Now the following files:

// foo.service.ts
@Injectable()
export class FooService extends AbstractFooProvider {
   ctor(private _fooDependency: SomeOtherFooService){}
   foo(): boolean {
     return this._fooDependency.isFoo();
   }
}

// foo.module.ts
@NgModule({
  declarations: [FooComponent],
  exports: [FooComponent]
})
export class FooModule {
   static withConfiguration(implementationProvider: Provider): ModuleWithProviders {
     return {
        ngModule: FooModule,
        providers: [implementationProvider]
     };
   }
}

// abstract-foo.provider.ts
export abstract class AbstractFooProvider {
    foo(): boolean;
}

// foo.component.ts
@Component({})
export class FooComponent {
   ctor(private _fooProvider: AbstractFooProvider){}
}

// app.module.ts    

export const FOO_PROVIDER : ClassProvider = {
  provide: AbstractFooProvider, 
  useClass: FooService
};

@NgModule({
   imports: [
      FooModule.withConfiguration(FOO_PROVIDER)
   ]
})
export class AppModule {}

Upvotes: 6

user184994
user184994

Reputation: 18281

You can use an InjectionToken:

export let SERVICE_A = new InjectionToken<MyService>('service.a');

Here, I've created an injection token for the interface MyService.

In my module, I match that token to a given implementation:

{ provide: SERVICE_A, useClass: ServiceImplA },

Then, in my component I specify which token to use:

constructor(@Inject(SERVICE_A) private service: MyService) { }

You can, of course, create a different token for each implementation.


Here is an example in StackBlitz. To see it in action, you can change the token from SERVICE_A to SERVICE_B

https://stackblitz.com/edit/angular-nwglpj?file=app%2Fhello.component.ts0

Upvotes: -1

Related Questions