1

I have an API class:

export class ApiService {

  constructor(public http: Http) { }

  put(controller: string, method: string, data: Object) {

    return this.http.put("http://127.0.0.1:8000",
      JSON.stringify(data), {
      })

    .map(res => res.json())

    .catch(err => {
      return Observable.throw(err.json());
    });

  }

}

and an AccountService class:

export class AccountService {

  api: ApiService;

  constructor() {
    this.api = new ApiService();
  }

  login(username: string, password: string) {

    return this.api.put("accounts", "login", { username: username, password: password});

  }

}

However when I run this example there are two problems:

1) The ApiService needs http in the constructor. Therefore this.api = new ApiService(); should provide Http which is not what I want.

How can I modify the ApiService so I don't have to provide Http to the constructor?

2) In the AccountService the this.api.put method is not found on the ApiService. Which I don't understand since I instantiated the ApiService into this.api

Bas van Dijk
  • 9,933
  • 10
  • 55
  • 91
  • It's entirely unclear what you try to accomplish. If you need `Http` to make an request, then how do you actually want it to get passed to the `ApiService`? Why don't you want `Http` to be passed by DI? – Günter Zöchbauer Jan 22 '16 at 13:31
  • It is PERFECTLY clear what he wants. I am having the same question myself. – Lucio Mollinedo Sep 21 '16 at 23:26

1 Answers1

2

In fact, you can get the instance to the ApiService into the AccountService one through dependency injection:

export class AccountService {
  constructor(private api: ApiService) {
  }
}

You simply need to register both services:

bootstrap(AppComponent, [AccountService, ApiService]);

Otherwise I don't see any reason why you can't use the put method of the ApiService from the AccountService.

Hope it helps you, Thierry

Thierry Templier
  • 198,364
  • 44
  • 396
  • 360
  • Ok but in this way I end up with an array of hundred services to register. I am using the `UpgradeAdapter` where the bootstrap looks like: `adapter.bootstrap(document.body, ["app"]);` I tried to add it as a provider but the AccountService doesn't see the ApiService. Thanks! – Bas van Dijk Jan 22 '16 at 13:40
  • In this case, you should try to use the method `adapter.addProvider`. I think that it's possible to provide directly an array of providers instead of single one at each time (see https://plnkr.co/edit/PRFgtXaCVEHGc1PSDbdc?p=info). It's the way Angular2 itself provides providers (for example HTTP_PROVIDERS, ROUTER_PROVIDERS). – Thierry Templier Jan 22 '16 at 13:48
  • It seems to work !:) But only when I add it with a provider and use `import {ApiService} from "./ApiService";` in the AccountService. Why are both needed? Any Thoughts? – Bas van Dijk Jan 22 '16 at 13:59
  • In fact, it's two different things. You use the class, so you need to import it (TypeScript behavior). An instance of this class is provided through the Angular2 dependency injection. So you need both ;-) – Thierry Templier Jan 22 '16 at 14:00
  • If you want to know more about how dependency injection works in Angular2, you could have a look at this reponse: http://stackoverflow.com/questions/34804298/whats-the-best-way-to-inject-one-service-into-another-in-angular-2-beta/34807397 ;-) – Thierry Templier Jan 22 '16 at 14:01
  • Clear, so otherwise I import the class itself and not the instance. Therefore I needed to add it to the bootstrap in order to get a singleton instance? – Bas van Dijk Jan 22 '16 at 14:03
  • 1
    Exactly! Angular2 needs a provider to be able to instantiate the class. So you need to register one for this particular class. In fact, `bootstrap(SomeComp, [ AccountService ]);` is a shortcut for `bootstrap(SomeComp, [ provide(AccountService, { useClass: AccountService }) ]);`. Perhaps it's easier to understand with the `provide` function... – Thierry Templier Jan 22 '16 at 14:06