How to use a service inside another service in Angular 2?

Injecting services into other services the easy way in Angular!

The problem…

I want to create a centralized service that provides utility functionality to other services in an Angular app. What is the best way to accomplish this?

Requirements:

  1. Have an Angular-Cli APP running
  2. Create a sample service
  3. Create a utility service that will be used in every service

The solution…

Let’s say you have a service that provides the ability to disable and enable a user. However, as a common piece of functionality, you also want to provide a utility service that will register when a user gets disabled and enabled, and keeps count of these actions (a far fetch example, however, it shows what we need to do to have injectable services within a service).

As you might know, in angular 2+, a service is just an exportable class.

Sample code of users.service.ts:
export class UsersService {
  addEnableUserEntry(id: number) {
    this.users[id].enabled = true; 
  }

  addDisableUserEntry(id: number) {
    this.users[id].enabled = false;
  }
}

Let us now import this service inside our app.component.ts.

import { Component, OnInit } from ‘@angular/core’;

import { UsersService } from ‘./users.service’;

@Component({
  selector: ‘app-root’,
  template: `app.component.html`,
  styles: [``]
})
export class AppComponent implements OnInit {
  constructor(private usersService: UsersService) {}
  users = [{name: ‘Mike’, active: false}, {name: ‘Molly’: active: true}]

  ngOnInit() {}

}

Lets create our utility service.

logging.service.ts contents:

export class LoggingService {
  logToConsole(message: string) {
    console.log(message);
  }
}

We want to add this utility service in AppComponent, because that is the top level of all components. If we need the service expose to all the sub components of app component, then it makes sense to add all the services inside the AppComponent.providers list in the Component metadata declaration. If we add it in AppComponent, you would think we are good and the service now works within the UsersService. However, the service when trigger returns an error: 

Cannot resolve all parameters for DataService(?). Make sure they all have valid type or annotations.

Problems again in services

Problems again…

We have now added our service into our AppComponent. However, even though we don’t see an error in the console window, our app is not behaving as expected. Nothing is happening, our users enable field is not changing from true to false and vice versa. What could be going wrong?

In our example, we want to use the UsersService inside AppComponent, but we also want to inject our utility service into our UsersService. Given the way Angular is built, we are not able to inject a service in another service when adding to AppComponent providers property.  We should remove all services declared in AppComponent providers list.

This is required in order for our Component to not override the top level instance created by the Angular framework. 

The only way we can make  this currently happen in Angular 2+ is to include both services in the providers list of the NgModule decorator. 

Example:

@NgModule({
  declarations: [
    ...
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule
  ],
  providers: [UsersService, LoggingServices],
  bootstrap: [AppComponent]
})
export class AppModule { }

Like it states in the angular documentation, click here

“You need it because Angular requires constructor parameter metadata in order to inject a Logger.”

This is true; if you notice, when declaring a service class we do not provide any metadata like a component or a directive does by using the @Component and the @Directive decorators respectively.

Let’s update our UsersService to show how it should now look like:

import { Injectable } from ‘@angular/core’;

import { LoggingServices } from ‘./logging.service’

@Injectable()
export class UsersService {
  constructor(private loggingService: LoggingService) {}

  addEnableUserEntry(id: number) {
    this.users[id].enabled = true; 
    this.loggingService.logUserChange(‘User: ‘ + this.users[id] + ‘ was enabled.');
  }

  addDisableUserEntry(id: number) {
    this.users[id].enabled = false;
    this.loggingService.logUserChange(‘User: ‘ + this.users[id] + ‘ was disabled’);
  }
}

I hope this was helpful. Please stay tuned until the next one!

Regards,

-Valhalam

Leave a Reply

Your email address will not be published. Required fields are marked *