Angular Level:
Angular's modular system provides you with the ability to create Components and Services.
While Components should be focused on the view, meaning the html template, a Service should be used for the application logic. While, from my experience, they are mostly used for HTTP requests, Services mayfulfill other purposes as logging or validation. Many Services will be reused throughout one application.
When reusing Services, it is important to think about the scope, in which you want to provide it.
Angular basically offers three scopes:
- Root Scope
- Module Scope
- Component Scope
The Root Scope
The root scope is the most commonly used scope for providing Services as it is also the default scope when creating a Service via Angular CLI.
@Injectable({
providedIn: 'root'
})
export class ExampleService {}
The default providedIn
argument in the CLI generated Service above means that the Service will be provided in the application root, the AppModule. Therefore the Service will be a singleton, meaning that there will be only one instance of this Service even if it is injected in multiple Modules and used in multiple Components or Directives.
Hint: Using the providedIn
argument in @Injectable
can also optimize bundle sizes if a service isn't used, which is especially useful for writing libraries. More info in the Angular Docs
The Module Scope
The same way we can provide the Service in Module scope:
@Injectable({
providedIn: 'ExampleModule'
})
export class ExampleService {}
But what if we don't want to share the service between modules?
We can then (instead of provideIn
) use the providers array in the corresponding @NgModule
:
@NgModule({
...
providers: [
ExampleService
]
})
export class ExampleModule {}
This way an instance of the service is created for the Module. If the service is added to the providers
array of multiple Modules, each Module gets its own Service instance.
The Component Scope
We can also create an individual Service instance for a Component by using the Component scope:
@Component({
...
providers: [ExampleService]
})
export class ExampleComponent{}
Let's see this in action
Let's get our hands dirty and create an example application using Module Scope and Component Scope.
I've used the Angular CLI to create a project with the following structure:
There is only one Service, which is located in the SharedModule
:
@Injectable()
export class ExampleService {
name = "Frank";
constructor() {
}
}
This Module and therefore the Service is used two other modules which both are then imported in the AppModule
.
-
The
ComponentScopeModule
which uses the Component Scope and consists of two components-
ExampleComponent1
which provides an input for the service's propertyname
@Component({ selector: 'component-scope-example1', template: `<input [(ngModel)]="service.name">`, providers: [ExampleService] }) export class Example1Component { constructor(readonly service: ExampleService) { } }
-
ExampleComponent2
which just displays the service's propertyname
@Component({ selector: 'component-scope-example2', template: `<p>{{service.name}}</p>`, providers: [ExampleService] }) export class Example2Component { constructor(readonly service: ExampleService) { } }
-
-
The
ModuleScopeModule
which uses the Module Scope and consists of two similar components.
The difference is, that the Components don't use theproviders
array. Instead the Service is provided
in the Module:
@NgModule({ declarations: [Example1Component, Example2Component], imports: [ CommonModule, SharedModule, FormsModule ], exports: [ Example1Component, Example2Component ], providers: [ ExampleService <--- it's provided here instead ] }) export class ModuleScopeModule { }
All four Components are then displayed using the AppComponent
:
<div>
<h1>Module Scoped</h1>
<module-scope-example1></module-scope-example1>
<module-scope-example2></module-scope-example2>
</div>
<div>
<h1>Component Scoped</h1>
<component-scope-example1></component-scope-example1>
<component-scope-example2></component-scope-example2>
</div>
And finally this is what we get:
We can see that in the "Module Scoped" section both components use the same service and therefore the input of the first component changes the output of the second component.
In the "Component Scoped" section this does not work as there are two service instances created,
one for each component.
Thanks for reading!
Cheers Julian
Top comments (3)
Hi Cheers Julian
Please send me the source code of this article!
Thank you!
To email: anhdnitt2008@gmail.com
Excelente!!