Services in Angular (Dependency Injection)

angular services

This article on Services in Angular is part of the Learning Angular series.

To write reusable tasks that can be used across multiple components. This is called as Services in Angular.
Duplication of Code and Data persistence are two use-cases of Services in Angular.

Why would you need Services

When app becomes large, it is very difficult to manage the code and replicate them at multiple places. Services come to rescue.

Creating a Logging Service

A Service file is just a normal Typescript file and doesn’t need any declaration like that of @Component or @Directive.
One can import, initialize and access the functions in it.
mycomponent.component.ts

onAccountCreated(accountStatus:string) {
    const loggingService:LogginService = new LoggingService();
    logginService.logStatusChange(accountStatus);
}

While one can use the service the above way, it is not the right way of doing it in Angular.

Injecting the Logging Service into Components

This can be done by instantiating it in the constructor

@Component({
    templateUrl: …
    …
    providers: [LoggingService]
})
export class AccountComponent {
    // This line in the constructor tells Angular that an instance of the LoggingService is required by this class.
    constructor(private loggingService:LoggingService) { }
    someFunction() {
        this.loggingService.printInfo("Some string");
    }
}

TODO: While it is explained in this lecture about why the providers is required to use the LoggingService, it is not quite clear. Search for more info.

Creating a Data Service

While multiple services were injected to the required classes, changes were getting logged, but the given accounts array isn’t getting updated.

Understanding the Hierarchical Injector

When something is injected to a component, it is initialized for that component and all its child components.
The highest possible level is AppModule. It will provide the same level throughout the app. With it, the same instance of the Service is available throughout the Application.
Then is the AppComponent. If injected to it, the same instance of the Service will be available for all the components, but not for the other Services.
If injected to any other component, it will only be available to the component as well its children.
If the same Service is provided in any Component and in any of its Parent, then the Service in the Child Component (available by the Parent component) will get overwritten with the one provided in the component.

How many Instances of Service it should be

So to make it work what we created in Lecture 98, the concept of Lecture 99 need to be applied.
As we already had provided the AccountsService in the AppComponent, and were again providing it in the ChildComponents, the instance was getting overwritten. So there were two different instances running in the AppComponent as well as the ChildComponent.
To make sure that things work, we need not provide the AccountsService in the ChildComponent again. But the constructor declaration is required to make the variable accessible.

Injecting Services into Services

One service can be used inside another by injecting it in the other.
The service which needs to be injected in any other service needs to be Provided in the AppModule.
Make the Service Injectable in which the other service is going to be called/initialized.
Then initialze it in the constructor.

@Injectable() // Import Injectable from '@angular/core'
export class AccountsService {
    constructor(private loggingService:LoggingService) { }
    ...
}

Using Services for Cross-Component Communication

AccountsService {
    ...
    statusUpdated = new EventEmitter();
    ...
}
AccountComponent {
    ...
    onSetTo(status) {
        this.accountsService.statusUpdated.emit(status);
    }
    ...
}
NewAccountComponent {
    ...
    someFunction() {
        this.accountsService.statusUpdated.subscribe(
            (status:string) => {
                alert("New status: " + status);
            });
    }
}

Using a Service for Cross-Component Communication

Events are being caught in the hierarchial mode. See if they can be caught by anyone implementing the service.

Passing Ingredients from Recipes to the Shopping List (via a service)

Spread operator …
Normally if we have an array of items, TypeScript provides a way in which they can be added to another array without looping through them all.

array1.push(...array2);

This will push the elements of array2 into array1.

Leave a Reply