8

I'm little bit confused in this two scenarios, we mark some classes with @Injectable() decorator so that they become available for injection to different components. I just want to know What is the difference between @Inject() and constructor injection as normal.

Scenario 1 - Using @Inject() :

@Component({
    selector: 'main-app',
    template: `
        ....
        {{_service.getName()}}
        ....
    `
})
export class AppComponent{
    constructor(@Inject(AppService) private _service){}
    ....
}

Scenario 2 - Using as a Normal parameter :

@Component({
    selector: 'main-app',
    template: `
        ....
        {{_service.getName()}}
    `
})
export class AppComponent{
    constructor(private _service:AppService){}
    ....
}

Both scenarios are working, is there any difference ? which one should is more preferable ?

Sagar Ganesh
  • 2,454
  • 3
  • 20
  • 32
  • Possible duplicate of [How to use Dependency Injection (DI) correctly in Angular2?](http://stackoverflow.com/questions/36109555/how-to-use-dependency-injection-di-correctly-in-angular2) – Ankit Singh Oct 13 '16 at 09:55

1 Answers1

23

You really should only use @Inject for situations where the injectable token is not a class. If you are unfamiliar with what a token is, it is basically what Angular uses to recognize what to inject. For example

providers: [
  AuthService,
  { provide: Http, useValue: new CustomHttpImpl() }
]

Here we have two different providers, the AuthService and the CustomHttpImpl. With the AuthService the token is AuthService. This means that we inject AuthService, using obviously the AuthService type

constructor(private authService: AuthService) {}

With this constructor, Angular knows to look for the AuthService with the token AuthService.

In the second provider, we provide a CustomHttpImpl but this time we use the token Http. So we cannot inject CustomHttpImpl we need to inject Http, since that is the token

// this will actually be the CustomHttpImpl, not Angular's Http
constructor(private http: Http)

// error: No provider for CustomHttpImpl
constructor(private http: CustomHttpImpl)

So you can tell from this that the tokens are all classes, which is enough for Angular to figure out to how to inject.

But let's say we have a String, or an Array of something we want to inject. We can't tie that to any class token, so we need to create an artificial token

import { OpaqueToken } from '@angular/core';

let numbers = [ 1, 2, 3, 4 ];
let config = '{ "some": "json", "config": "data" }'

const NUMBERS = new OpaqueToken('app.numbers');
const CONFIG = new OpaqueToken('app.config');

Now we have tokens for the items we want to inject. When we configure the providers, we use those tokens, and when we inject, we @Inject(TOKEN)

providers: [
  { provide: NUMBERS, useValue: numbers },
  { provide: CONFIG, useValue: config }
]

constructor(@Inject(NUMBERS) numbers: number[], @Inject(CONFIG) config: string)

UPDATE

Now, with Angular 4, we should use InjectionToken rather than OpaqueToken

Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
  • nice, I really appreciate your response. I got it. – Sagar Ganesh Oct 13 '16 at 12:20
  • BTW - Before the "But let's say we have a String, " i would have add the example of strings tokens ( without OpaqueToken) so they can see where is the problem with collusion. which leads to what you've written about opaques. – Royi Namir Apr 07 '17 at 09:36
  • @peeskillet I am a little confused. `OpaqueToken` is a class, and `InjectionToken` extends `OpaqueToken`. Why do I have to use `@Inject` with these? – gravidThoughts Apr 20 '17 at 13:31
  • @gravidThoughts These are two kind of unrelated things. You should post another question with a code example. It's kind of hard to explain where you're understanding has gone wrong without seeing an example of what you mean – Paul Samsotha Apr 20 '17 at 13:36
  • I discovered recently that there are times when using @Inject actually is worse, not just an alternative. Looking at `@Inject(type) myVar:type` vs. `myVar:type` in the constructor the former seems to prevent method checking, so I can code `myService.serviceFunc()` and TypeScript doesn't complain if `serviceFunc()` doesn't exist on the service. However, if I use the second method, it does give me an error (as it should) and won't transpile. – redOctober13 Nov 16 '17 at 17:21