24

I have 2 services one.service.ts and two.service.ts, and a component dashboard.component.ts.

How to conditionally inject those service into the component?

import { Component, ViewEncapsulation, Inject } from '@angular/core';
import { OneService } from '../services/one.service';
import { TwoService } from '../services/two.service';

@Component({
  selector: 'dashboard',
  encapsulation: ViewEncapsulation.Emulated,
  styleUrls: ['./dashboard.less'],
  templateUrl: './dashboard.html'
})
export class DashboardComponent {
    constructor() {
       // Here how do I get service instance based on some this condition.
         if(true) {
             /* Service **one.service.ts** to be injected */
         } else {
             /* Service **two.service.ts** to be injected */    
         }

    }
}
Alexander Abakumov
  • 13,617
  • 16
  • 88
  • 129
Ajey
  • 7,924
  • 12
  • 62
  • 86
  • 1
    Use `useFactory` or `injector.get` – yurzui Apr 17 '17 at 11:12
  • Or maybe create specific instances of DashboardComponent. It seems weird that this component be that polymorphic to a point of using two services. I might be wrong of course as we miss the domain context – Sebas Apr 17 '17 at 11:43

2 Answers2

40

You can use the Injector

import { Injector } from '@angular/core'  
...
constructor(private injector: Injector){ 

  if(true) {
    this.oneService = <OneService>this.injector.get(OneService);
  } else {
    this.twoService = <TwoService>this.injector.get(TwoService);
  }
}

As @MeirionHughes mentioned this is called the service locator pattern:

The technique is an example of the service locator pattern.

Avoid this technique unless you genuinely need it. It encourages a careless grab-bag approach such as you see here. It's difficult to explain, understand, and test. You can't know by inspecting the constructor what this class requires or what it will do. It could acquire services from any ancestor component, not just its own. You're forced to spelunk the implementation to discover what it does.

Framework developers may take this approach when they must acquire services generically and dynamically.

Source: https://angular.io/docs/ts/latest/guide/dependency-injection.html#!#explicit-injector

And again as mentioned you can get these injectors in another service and then inject this service into your component.

Community
  • 1
  • 1
eko
  • 39,722
  • 10
  • 72
  • 98
  • 1
    Sorry, this is bad practice, you're breaking the IoC paradigme, which is the only reason why you'd have (injectable) services in the first place. The answer is very good technically (I learned from it) but I have to downvote it – Sebas Apr 17 '17 at 11:46
  • 1
    I've removed my down-vote (its useful at least as last resort) but I recommend people look up making a Provider/Builder/Factory/Facade and avoid injector.get() – Meirion Hughes Apr 17 '17 at 11:50
1

In other words you want to achieve Bridge or Abstract Factory pattern. In this case you can use useFactory. Related post.

Vugar Abdullayev
  • 1,852
  • 3
  • 21
  • 46