Create a reusable angular service
Tags: angular, architecture
Published: 2020-01-14 08:29:30

# 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.
```typescript
@Injectable()
export class ReuseService {
  name: string = 'reuse me!'; 
}
``` 

Provide the service on module level.
```typescript
@NgModule({
  // imports, declarations, ....
  providers: [ReuseService]
})
export class AppModule { }
```

And use it in you're component
```typescript
@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:
```typescript
// 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.
```typescript 
@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](https://angular.io/guide/dependency-injection-providers#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

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

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

@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
```typescript
@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.

```typescript
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.

```typescript

@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
```typescript
@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, ){}
}
``` 
{% stackblitz angular-reuse-services %}