TomKeegasi
TomKeegasi

Reputation: 210

Why do I still need @inject in this angular2 example?

This is proably a special case (injecting the browsers native window object), but nevertheless I'm a bit confused about why I still need the @Inject() parameter-decorator when my class already has a @Injectable() decorator.

Take this simplified example:

import { provide, bootstrap, Injectable, Inject } from '@angular/core';


@Injectable()
export class Token {
  private token: string;

  public constructor(token: string, window: Window) {
    this.token = window.atob(token);
  };

  public getToken(): string {
    return this.token;
  }
}


@Injectable()
export class TokenFactory {
  private window: Window;

  public constructor(window: Window) {
    this.window = window;
  }

  public createToken(token: string): Token {
    return new Token(token, this.window);
  }
}


@Component({
  template:   `
    <p *ngFor="let token of tokens">
      Encoded: {{token.getToken()}}
    </p>
  `,
  providers:  [ TokenFactory ]
})
class MainComponent {
  public tokens: Token[];

  public constructor(factory: TokenFactory) {
    this.tokens = [
      factory.create('token-1'),
      factory.create('token-2')
    ];
  };
}


bootstrap(
  MainComponent, [
    provide(Window, { useValue: window })
]);

Overview: We have a token class that represents an object that could exist multiple times inside a component or another service (so no singleton). The token class depends on the global window object (eg. for base64 encoding). To make this testable we define an app-wide provider for the global window object during bootstrap instead of using it directly in the token service.

The main component needs to create tokens dynamically, so we create and inject a simple factory-service TokenFactory which also needs the window provider (to pass it the the token class during construction).

The Problem: This fails when executed in a browser with the error

Can't resolve all parameters for TokenFactory: (?).

but can be fixed by adding a @Inject(Window) decorator to the factories constructor window parameter.

Now, I'm a bit confused, since most guides/tutorials explain that the inject decorator is not required in typescript when decorating the class with the Injectable decorator, so why does the example fail without using @Inject() decorator?

Config: emitDecoratorMetadata and experimentalDecorators settings are enabled and I'm using tsc 1.8.10 and angular2 rc.3.


PS: I'm also open for general design improvements.

(Eg. In a production scenario I would probably only export the Token interface and not the whole class)

Upvotes: 2

Views: 2212

Answers (1)

G&#252;nter Z&#246;chbauer
G&#252;nter Z&#246;chbauer

Reputation: 657308

It's unclear to me what the question actually is about but

type string for a constructor parameter of an injectable doesn't make any sense without @Inject(...)

@Injectable()
export class Token {
  private token: string;

  public constructor(token: string, window: Window) { // <<== invalid
    this.token = window.atob(token);
  };

  public getToken(): string {
    return this.token;
  }
}

but because you are using it like

new Token(token, this.window);

it seems that just @Injectable() should be removed from this class.


About the error message: It looks like Window is not properly imported or it is not a type but an OpaqueToken or a string.

@Inject() is required if a key that differs from the parameter type should be used by dependency injection. In your case it looks like Window is not a type (class) and therefore doesn't work when used as such.

Upvotes: 5

Related Questions