3

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?

3
  • Have a look at angular.io/guide/dependency-injection#ngmodule-providers, you can specify which value to provide Commented Jan 20, 2018 at 13:53
  • 1
    I have already checked the guide. I am not providing a value! I need to provide a service that has its own set of dependencies. Please read the question, and ask for clarifications if needed. Commented Jan 20, 2018 at 13:58
  • 1
    Why the downvote? I think this a good question. Maybe you could add any sort of research/implementation efforts that you have done until now, OP Commented Jan 20, 2018 at 15:31

2 Answers 2

6

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 {}
Sign up to request clarification or add additional context in comments.

Comments

-1

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.