DEV Community

Sanket Maru
Sanket Maru

Posted on

Are your Angular Services Singleton ?

Angular has the concept of services which allows to share the data between components.

In this blog we will learn about service instances creation in Angular.

What happens when we inject service in root of a lazy module, is the same instance used for multiple lazy modules.

What if we want to have a separate instance per module and per component ?

We will use the same code example as used in common chunks example. If you haven't gone through that blog do checkout to learn on why common chunks are created.

Let's begin then.

Common Service Instance

Let's start where we ended in the previous post. We have two lazy modules user and account and currently share the same toast module which is built in a separate chunk.

As we have given as @Injectable({ providedIn: "root" }) for the toast service, a singleton instance of service is created and is shared among all the lazy modules.

As toast module is shared, we will have a common count of messages for both the modules.

Lets see it in action below -

Service Instance per Component

We can see the count of toast message is common and also toast module is included in the common chunk.

However, now we want to keep a count of how many times user clicks the button in a particular module. Individual count for user module and account module.

We will tweak the code in individual components and see how it behaves.

@Component({
  selector: 'app-account',
  templateUrl: './account.component.html',
  styleUrls: ['./account.component.scss'],
  providers: [ToastService]
})
export class AccountComponent {
  ...code
}

@Component({
  selector: 'app-user',
  templateUrl: './user.component.html',
  styleUrls: ['./user.component.scss'],
  providers: [ToastService]
})
export class UserComponent {
  ...
}
Enter fullscreen mode Exit fullscreen mode

Above code with create two instances of ToastService which will be respective to user component and account component.

Service Instance per Module

Great, we have multiple instance of service created and also toast module code is in common chunk.

As its seen, the count is always reset to 0. This is because the service instance is getting destroyed as soon as component is destroyed. When user navigates to a new route, earlier component is destroyed and new is created.

As we are creating instance at component level, we get a new instance every time. This might be useful if we want to reset the count.

To solve this we will create the instance at module level, so it will have a single instance for a particular module and also code will be served from common chunk.

To do this add ToastService in providers section of module which can be done from code as below -

@NgModule({
  declarations: [
    UserComponent
  ],
  imports: [
    CommonModule,
    UserRoutingModule,
    ToastModule
  ],
  providers: [ToastService],
  exports: [ToastModule]
})
export class UserModule { }

@NgModule({
  declarations: [
    AccountComponent
  ],
  imports: [
    CommonModule,
    AccountRoutingModule,
    ToastModule
  ],
  providers: [ToastService],
  exports: [ToastModule]
})
export class AccountModule { }
Enter fullscreen mode Exit fullscreen mode

Let's see now in action how the behaviour is.

Great, now we have service instance per module and it stores the count for a particular lazy module.

Service Injection at App Root

Coming to the last case if we include toast service to the main app module.

This can be done by importing in providers section of app module.

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    ToastModule
  ],
  providers: [ToastService],
  bootstrap: [AppComponent]
})
export class AppModule { }
Enter fullscreen mode Exit fullscreen mode

Lets see the demo.

With this, now we have 3 instances of toast service.

  1. For App Module
  2. User ( Lazy ) Module
  3. Account ( Lazy ) Module

Even if don't have the providers section in main app module, it will still have three separate instance for app and respective lazy modules as in service injectable we have providedIn as root.

For all modules present in app module, it would use instance of the app module one and instances of lazy modules would be separate.

This is because Angular creates separate injector tree for lazy module.

So, with this post we have learned scenarios in which a common service instance can be used per module or a component or by have it at root level.

Complete code can be found at my GitHub branch service_creation.

Thanks for checking this blog and let me know if you find it useful.

Discussion (0)