Create a reusable angular service

Bo Vandersteene
Jan 14 · 3 min read

Originally published on: https://dev.to/reibo_bo/create-a-reusable-angular-service-c0m

Create a reusable angular service

The goal is to create a service that can be reused throughout our Angular application.
The different kind of use cases this service would be usefull for would be like:

  • Call different APIs that return the same output format
  • Use different settings for that service
  • Have a local state inside the service, and that state should be different amongst different use cases

The most common way of using a service

By default we use services through dependency injection. Registering a dependency can be done in multiple ways.

  • Globally using provideIn: 'root' metadata on the service @Injectable decorator
  • On module level in the providers array of the module
  • On component level in the providers array of the component

Now let’s create a service that we’re not going to inject on the root level.
In this case we will inject it into the module.

For the purpose of the example a simple service is created.

@Injectable()
export class ReuseService {
name: string = 'reuse me!';
}

Provide the service on module level.

@NgModule({
// imports, declarations, ....
providers: [ReuseService]
})
export class AppModule { }

And use it in you’re component

@Component({
selector: 'my-app',
template: `
<ul>
<li>reuseService: {{reuseService.name}}</li>
</ul>
`
})
export class AppComponent {
constructor(public reuseService: ReuseService ){}
}

But now it turns out that the name should be set outside the service…

Use a factory

Factory’s are used to create a service dynamically. Sometime a value that we use inside the service don’t have exist until run time.

To use a factory inside angular, a factory provider should be created. This can be done through a function.

The reuseFactory, is responsible to get the name from somewhere else so the factory function looks as following:

// create the factory
export function reuseFactory(name: string){
return () => new ReuseService(name)
}

Now we want to give the responsibility of setting the name to our module. This can be done with a factory.

@NgModule({
// imports, declarations, ....
providers: [
// Provide you're service through a factory
{
provide: ReuseService,
useFactory: reuseFactory("reuse service")
},
]
})
export class AppModule { }

In this example we only inject a string, but it can also be an other provider.

More information on how to use factory providers: Angular Docs — factory providers

Create Injection Tokens

An injection token can be used in a DI provider. It can be used also to create unique names for service. Create a token.ts file and give an unique name for the token

export const REUSE  = new InjectionToken<ReuseService>('ReuseService1');

The token can be used in the provider section of the factory

@NgModule({
// imports, declarations, ....
providers: [
{
// use token instead of service class
provide: REUSE,
useFactory: reuseFactory("reuse service")
}
]
})
export class AppModule {}

Now the injection token can be used inside the component

@Component({
selector: 'my-app',
template: `
<ul>
<li>reuseService: {{reuseService.name}}</li>
</ul>
`
})
export class AppComponent {
constructor(@Inject(REUSE) public reuseService: ReuseService ){}
}

Use the service with different settings

Now we get to the point were we want to be albe to use the service multiple times with a different kind of configuration. This can be useful if you want to trigger different endpoints that return the same object format for example.

First some unique tokens will be created.

export const REUSE_1  = new InjectionToken<ReuseService>('ReuseService1');
export const REUSE_2 = new InjectionToken<ReuseService>('ReuseService2');
export const REUSE_3 = new InjectionToken<ReuseService>('ReuseService3');

These tokens will be used to define our services. In the example bellow we instantiate the service 4 times, each service will have its own instance of the service. If we add state to the services, they will not be shared amongst each other. They live on their own.

@NgModule({
// imports, declarations, ....
providers: [
{
provide: ReuseService,
useFactory: reuseFactory("reuse service")
},
{
provide: REUSE_1,
useFactory: reuseFactory("reuse 1")
},
{
provide: REUSE_2,
useFactory: reuseFactory("reuse 2")
},
{
provide: REUSE_3,
useFactory: reuseFactory("reuse 3")
}
]
})
export class AppModule {}

Now the different tokens can be used inside the component

@Component({
selector: 'my-app',
template: `
<ul>
<li>reuseService: {{reuseService.name}}</li>
<li>reuseService 1: {{reuseService1.name}}</li>
<li>reuseService 2: {{reuseService2.name}}</li>
<li>reuseService 3: {{reuseService3.name}}</li>
</ul>
`
})
export class AppComponent {
constructor(public reuseService: ReuseService,
@Inject(REUSE_1) public reuseService1: ReuseService,
@Inject(REUSE_2) public reuseService2: ReuseService,
@Inject(REUSE_3) public reuseService3: ReuseService, ){}
}

Example on stackblitz: https://stackblitz.com/edit/angular-shxsth?embed=1&file=src/app/app.component.ts

Bo Vandersteene

Written by

Frontend Software Engineer & Mentor, works with Angular, Typescript, Javascript.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade