Forcing New Service Instance Creation. Overriding Dependency Injection in Angular
Tags: angular, frontend, webdev, javascript
Published: 2024-04-04 14:18:27

Hi all! First post here! I want to share a post written by a colleague of mine at [MarsBased](https://marsbased.com) that I think should be posted here too, so my heartfelt thanks to David Garmendia for writing it. Let's start!

In Angular, injected services are determined by various factors that we cannot always directly control. Let's see some ways of overcome them.

Learning how to force the injector to create new instances instead of using existing ones can be a solution to typical problems that arise when using singleton objects. For example, when a service maintains state and is used from multiple places simultaneously.

The proper way to inject a service into our class is perfectly documented in one of the Angular documentation guides: [Introduction to services and dependency injection](https://angular.io/guide/architecture-services). This is the recommended way for most cases.

Usually, we can have sufficient control over service instances by specifying the service in components or modules through the providers attribute of these objects. For example, if at a certain point in our component and module hierarchy we want to ensure that a new instance of a service is created, we just have to declare it in that attribute.

```ts
@Component({
  standalone: true,
  selector:    'app-hero-list',
  templateUrl: './hero-list.component.html',
  providers:  [ HeroService ]
})
export class HeroListComponent {
```

In the above example, even though the `HeroService` service has been declared in a higher component or module, through the providers attribute of the component, we force the injector to create a new instance that will be used from this component downwards.

However, we cannot always or do not always want to use this method. An example is services that are instantiated at the root level and used from other services. Services do not have the providers attribute available, so it is not possible to force this instantiation from a service. It is possible that if the service is not at the root level, we can find a module or component that instantiates it, but it is not always possible.

In these cases, it is possible to use the dependency injector to force the creation of this new instance at the service level. For example, let's say we have the following two services.

```ts
@Injectable({providedIn: 'root'})
export class HeroService {
  private dataHeroService: DataHeroService = injectable(DataHeroService)
```

```ts
@Injectable({providedIn: 'root'})
export class DataHeroService {
  myStateNumber = 0
```

When using `DataHeroService` from HeroService we access the only instance (singleton) that exists of this service throughout the application. Since `DataHeroService` has internal state, there is a possibility that a third object modifies that state, thereby modifying the behavior of `DataHeroService` and consequently behaving unexpectedly from the point of view of HeroService.

If we wanted to ensure that HeroService gets a unique service instance that will not be shared with any other object in the application, we can do it like this.

```ts
@Injectable({providedIn: 'root'})
export class HeroService {
  private dataHeroService: DataHeroService;
  private injector = inject(Injector);

  constructor() {
    const injector = Injector.create({ providers: [DataHeroService], parent: this.injector });
    this.dataHeroService = injector.get(DataHeroService);
  }
```

In this example, we are using the static method Injector.create to create a new injector, to which we pass the service, or list of services, that we want to create and a reference to the current injector in order to resolve the dependencies that `DataHeroService` may have.

Once the new injector is instantiated, we can ask it for the instance of `DataHeroService` that will be unique in this context.