DEV Community

Alireza Razinejad
Alireza Razinejad

Posted on • Edited on

Service instances in Angular

What is instance?

In JavaScript instance simply mean a new child has been born with same DNA as their parent, and same DNA mean they have all their parents attributes.

So here(In JS world) Parent is Class which is, in our case it is service!

What is service?

Service is just another class which have been decorated with @Injectable()

When mark a class with this decorator we actually telling Angular to consider this class as injectable objects which can be used and injected into other classes.

Take this code as an example

@Injectable()
class MyService {}

@Component()
class MyComponent {
 constructor(private service: MyService) {}
}
Enter fullscreen mode Exit fullscreen mode

If we run our app this way, we will face error with title Null Injector which is saying that service is not provided any where so it is not usable!

That simply mean, this service does not have any instance available for our component to be used!

We have three way of creating Instances

Angular give us three way to create instance from our service, and those will cover every use cases we have.

Singleton Instance

Singleton mean, we will create only one instance!

Let's say we need to have a service to handle Authorization operations, of course we do not want to have two instance of that service, because maybe we do not want to use NgRx as state management as it is too complicate and we are too lazy to learn it!
So can store user related states in our service, but we need to make sure there is only one instance!

Angular made it as easy as the following code!

@Injectable({ providedIn: 'root' })
class MySingletonService {}
Enter fullscreen mode Exit fullscreen mode

The key is providedIn field, which will tell Angular to provide it in root of our app, so we will have one instance of our service in the app.

Instance per module

In the last section we can see we have provided the service in the root of the app.

But what if we want to create instance of our service per module!

For this to work, we can use feature Lazy loading.
Limiting provider scope by lazy loading modules

Let's say we have some main modules that require some functionalities which is the same per each one of them (Like API calls) and also those modules will need to store some state in the service which provide those functionalities (Store API responses) but stored states(data) should be unique per each module.

The solution is as simple as the following code.


@Injectable()
class MyService {}

@NgModule({providers: [MyService]})
class FirstModule{}

@NgModule({providers: [MyService]})
class SecondModule{}

@NgModule({providers: [MyService]})
class ThirdModule{}

Enter fullscreen mode Exit fullscreen mode
const routes: Routes = [
  {
    path: 'first-module',
    loadChildren: () => import('./first/first.module').then(m => m.FirstModule)
  },
  {
    path: 'second-module',
    loadChildren: () => import('./second/second.module').then(m => m.SecondModule)
  },
  {
    path: 'third-module',
    loadChildren: () => import('./third/third.module').then(m => m.ThirdModule)
  }
];

@NgModule({imports: [RouterModule.forRoot(routes)]})
class AppModule {}
Enter fullscreen mode Exit fullscreen mode

As you can see, we just provided the service to that module using providers field.

From now on every component that is declared in those module can safely inject that service and be sure any data which is stored in those services(instances) is unique.

In case your problem does not support route feature lazy loading, you could create a service per module and extend the main one.
Running Demo
Editor Version

Instance per component

This is amazing! I use this solution in my every day problem solving!

This one can help us keep components out of any complex logic and make them highly testable!

Let's say that have created a Facades layer to simplify access to data layer (Services which is responsible to make API calls and provide data to presentation layer).

Those facades layers should be exists on their own and they not even need to store anything in them!

So we can create them only when the component which needed that service is come alive and simply destroy it when component destroyed!

The solution is as simple as just provide it to component!!!

@Injectable()
class MySrvice {}

@Component({
 providers: [MyService]
})
class MyComponent {
 constructor(private service: MyService) {}
}
Enter fullscreen mode Exit fullscreen mode

How to destroy it with component?

@Injectable()
class MySrvice implements OnDestroy {}
Enter fullscreen mode Exit fullscreen mode

Yes!! we can implement OnDestroy interface/lifecycle on service this way!

And now we know the three way of creating instances of our services in Angular.

Thank you for your time and reading this.
Hope you liked.

Top comments (0)