Ang2

Angular Services

Learn how to create reusable functionality within a service that components can access via dependency injection.

Up to date (Apr '19) Angular

Services allow for greater seperation of concerns for your application and better modularity by allowing you to extract common functionality out of components. Angular also comes with its own dependency injection framework for resolving dependencies, so you can have your services depend on other services throughout your application, and dependency injection will resolve your dependencies for you.

Dependency Hierarchy

Each instance of component has an injector, and when a dependency is requested it looks at its own injector to see if it has the dependency. If it doesn't, it will look at its parent component's injector, until it reaches the root component of your app. The injectors are responsible for instantiating the services and keeping track of them for child components to use. This behavior is slightly different from dependency injection in AngularJS, where the injector tree was flat and were tied to individual modules.

Services need to be registered in the providers array at the parent-most component that will be using it. There will one instance of your service per injector, so registering a service more than once can cause your app to have multiple instances of the same service in your child components.

It's also worth noting that not all services are singletons. They can be if you register them in the AppModule that's used for bootstrapping, but there may be cases where you want to register a service at a child-level component, where each instance of that component gets their own instance of the service. This is the exception however, and not the rule. See the Provider Scope section of the Angular docs for more clarity.

The @Injectable Decorator

The @Injectable() decorator is needed when a Service needs dependencies injected to its constructor. Although it is optional when a service doesn't need dependencies injected into it, a common practice is to use the Injectable() decorator for all services for consistency and so that when a service requires dependencies in the future you don't have to worry about remembering to add the decorator. Services generated by the Angular CLI will automatically be created with @Injectable along with a new property called providedIn. providedIn instructs the application where to provide the service. This allows you to only provide a service in a particular module. This also enables tree shaking so the service won't be included in the application if the module is not being used.

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Injectable({
  providedIn: 'root',
}) // The Injectable decorator is required for dependency injection to work
export class RepoService{
  constructor(private http: HttpClient){
  }

  fetchAll(){
    return this.http.get('https://api.github.com/repositories');
  }
}

Make sure that the parenthesis are present when using the @Injectable() decorator. Using @Injectable won't properly apply the decorator to your service.

Additional Reading

Dependency Injection Guide

Dependency Injection Overview

Hierarchical Dependency Injection Guide

 

I finished! On to the next chapter