Search code examples
angulardependency-injectionangular-servicesangular-components

Is there a way to inject a service into a component from the parent component?


So I have a table component. But the table component will need to use the appropriate API service depending on whether it is called by ComponentA or ComponentB.

For instance, if ComponentB uses TableComponent, then it needs to make TableComponent inject the APIForB service and use it to populate the table.

New to angular so not sure if such a thing is possible.


Solution

  • Well the DI-system of angular is hierarchical that means that:

    services are singletons within the scope of an injector

    And Angular will create nested injectors with own service instances, whenever it creates instances of components, which define providers in their @Component decorator.

    For you this means, that you can provide different service implementations for your components, those service implementations have to extend the same abstract class and you inject the abstract class to your TableComponent:

    APIService:

    export abstract class APIService{
      yourMethod1:() => void ;
      ...
    }
    

    You have to define your base class as abstract class and not an interface, because interfaces do not exist at runtime and therefore they are no valid DI-Tokens.

    APIforAService/APIforBService:

    @Injectable()
    export class APIforAService implements APIService{
      youMethod1Implementation(){...}
      ....
    }
    

    Of course you do the same with the APIforBService but with the different implementation.

    TableComponent

    Now in your TableComponent you inject APIService but define no providers!

    @Component({
      selector: 'your-selector',
      templateUrl: '',
      providers: []
    })
    export class TableComponent {
      constructor(private apiService: APIService) {
      }
    }
    

    ComponentA/B

    And now in you ComponentA and ComponentB you define the appropriate providers:

    @Component({
      selector: 'componentA',
      templateUrl: '',
      providers: [{
        provide:APIService,
        useClass:APIforAService
      }]
    })
    export class ComponentA {
      
    }
    

    And here you also do the same with ComponentB and use APIforBService.

    Because of the hierarchical DI-System your TableComponent gets APIforAService if instantiated from ComponentA and APIforBService if instantiated from ComponentB