Search code examples
angulartypescriptdesign-patternsinversion-of-control

Doing Inversion of Control (IoC) in Angular


Consider we have an interface called MapService, and two implementations: GoogleMapsService and LeafletMapService. I want a package (or Angular2?) to call the needed implementation rather than developers.

export interface MapService {
//define my API
}

@Injectable()
export class GoogleMapsService implements MapService {
//implement the API
}

That means, in the component I want the type of the service to be the interface (so not depending on the implementation):

import { Component } from '@angular/core';
import { MapService } from './map.service';
import { GoogleMapsService } from './google-maps.service'; 

@Component({
    template : `...`,
    providers: [GoogleMapsService]
})

export class MyComponent  {

  constructor(private googleMapsService : MapService) { //notice the type of the service here
  }
}

How can I achieve that?


Solution

  • So based on @jb-nizet's great comment; I've managed to do what I want using InjectionToken. Here is a code snippets:

    import { Injectable, InjectionToken } from '@angular/core';
    export const GOOGLE_MAPS_IMPL = new InjectionToken<MapService>('googleMapImpl');
    
    export interface MapService {
    //define the API
    }
    
    @Injectable()
    export class GoogleMapsService implements MapService {
    //implement the API
    }
    

    And the component:

    import { Component, Inject } from '@angular/core';
    import { MapService } from './map.service';
    import { GoogleMapsService, GOOGLE_MAPS_IMPL } from './google-maps.service'; 
    
    @Component({
        template : `...`,
        providers: [{ provide: GOOGLE_MAPS_IMPL,  useClass:   GoogleMapsService }]
    })
    
    export class MyComponent  {
      constructor(@Inject(GOOGLE_MAPS_IMPL) private googleMapsService : MapService) { 
      }
    }