Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the best way to inject one service into another in angular 2 (Beta)?

I know how to inject a service into a component (via @Component), but how can I use DI to pass around services outside of components?

In other words, I don't want to do this:

export class MyFirstSvc {  }  export class MySecondSvc {     constructor() {         this.helpfulService = new MyFirstSvc();     } }  export class MyThirdSvc {     constructor() {         this.helpfulService = new MyFirstSvc();     } } 
like image 558
Bryce Johnson Avatar asked Jan 15 '16 04:01

Bryce Johnson


People also ask

Can we inject a service into another service in Angular?

Angular provides the ability for you to inject a service into a component to give that component access to the service. The @Injectable() decorator defines a class as a service in Angular and allows Angular to inject it into a component as a dependency.

How many ways we can inject service in Angular?

There are three types of Dependency Injections in Angular, they are as follows: Constructor injection: Here, it provides the dependencies through a class constructor. Setter injection: The client uses a setter method into which the injector injects the dependency.

What is injectable () Angular?

@Injectable() lets Angular know that a class can be used with the dependency injector. @Injectable() is not strictly required if the class has other Angular decorators on it or does not have any dependencies.

What is dependency injection in Angular 2 with example?

Dependency injection, or DI, is one of the fundamental concepts in Angular. DI is wired into the Angular framework and allows classes with Angular decorators, such as Components, Directives, Pipes, and Injectables, to configure dependencies that they need.


1 Answers

Yes, the first thing is to add the @Injectable decorator on each services you want to inject. In fact, the Injectable name is a bit insidious. It doesn't mean that the class will be "injectable" but it will decorate so the constructor parameters can be injected. See this github issue for more details: https://github.com/angular/angular/issues/4404.

Here is my understanding of the injection mechanism. When setting an @Injectable decorator for a class, Angular will try to create or get instances for corresponding types in the injector for the current execution chain. In fact, there is not only one injector for an Angular2 application but a tree of injectors. They are implicitly associated to the whole application and components. One key feature at this level is that they are linked together in a hierarchical way. This tree of injectors maps the tree of components. No injectors are defined for "services".

Let's take a sample. I have the following application:

  • Component AppComponent: the main component of my application that is provided when creating the Angular2 application in the bootstrap function

    @Component({   selector: 'my-app',      template: `       <child></child>     `,     (...)     directives: [ ChildComponent ] }) export class AppComponent { } 
  • Component ChildComponent: a sub component that will be used within the AppComponent component

    @Component({     selector: 'child',      template: `       {{data | json}}<br/>       <a href="#" (click)="getData()">Get data</a>     `,     (...) }) export class ChildComponent {   constructor(service1:Service1) {     this.service1 = service1;   }    getData() {     this.data = this.service1.getData();       return false;    } } 
  • Two services, Service1 and Service2: Service1 is used by the ChildComponent and Service2 by Service1

    @Injectable() export class Service1 {   constructor(service2:Service2) {     this.service2 = service2;   }    getData() {     return this.service2.getData();   } } 

    @Injectable() export class Service2 {    getData() {     return [       { message: 'message1' },       { message: 'message2' }     ];   } } 

Here is an overview of all these elements and there relations:

Application      | AppComponent      | ChildComponent   getData()     --- Service1 --- Service2 

In such application, we have three injectors:

  • The application injector that can be configured using the second parameter of the bootstrap function
  • The AppComponent injector that can be configured using the providers attribute of this component. It can "see" elements defined in the application injector. This means if a provider isn't found in this provider, it will be automatically look for into this parent injector. If not found in the latter, a "provider not found" error will be thrown.
  • The ChildComponent injector that will follow the same rules than the AppComponent one. To inject elements involved in the injection chain executed forr the component, providers will be looked for first in this injector, then in the AppComponent one and finally in the application one.

This means that when trying to inject the Service1 into the ChildComponent constructor, Angular2 will look into the ChildComponent injector, then into the AppComponent one and finally into the application one.

Since Service2 needs to be injected into Service1, the same resolution processing will be done: ChildComponent injector, AppComponent one and application one.

This means that both Service1 and Service2 can be specified at each level according to your needs using the providers attribute for components and the second parameter of the bootstrap function for the application injector.

This allows to share instances of dependencies for a set of elements:

  • If you define a provider at the application level, the correspoding created instance will be shared by the whole application (all components, all services, ...).
  • If you define a provider at a component level, the instance will be shared by the component itself, its sub components and all the "services" involved in the dependency chain.

So it's very powerful and you're free to organize as you want and for your needs.

Here is the corresponding plunkr so you can play with it: https://plnkr.co/edit/PsySVcX6OKtD3A9TuAEw?p=preview.

This link from the Angular2 documentation could help you: https://angular.io/docs/ts/latest/guide/hierarchical-dependency-injection.html.

Hope it helps you (and sorry the long answer), Thierry

like image 58
Thierry Templier Avatar answered Sep 20 '22 04:09

Thierry Templier