Provider Scopes in Angular
Tags: angular, typescript
Published: 2020-07-04 13:31:51

### Angular Level:

![level](https://raw.githubusercontent.com/Nas3nmann/articles/b09b6860c561037e223a104a6e824c371b7444ec/Angular/shared/angular-levels/ng_2_of_5.svg)

---

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:
1. Root Scope
2. Module Scope
3. 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.
```typescript
@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](https://angular.io/guide/hierarchical-dependency-injection#tree-shaking-and-injectable)*

## The Module Scope
The same way we can provide the Service in Module scope:
```typescript
@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`:
```typescript
@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:

```typescript
@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:
![Project structure](https://raw.githubusercontent.com/Nas3nmann/articles/master/Angular/provider-scope/example-project-tree.png)

There is only one Service, which is located in the `SharedModule`:
```typescript
@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`.
1. The `ComponentScopeModule` which uses the **Component Scope** and consists of two components
    1. `ExampleComponent1` which provides an input for the service's property `name`
        ```typescript
        @Component({
          selector: 'component-scope-example1',
          template: `<input [(ngModel)]="service.name">`,
          providers: [ExampleService]
        })
        export class Example1Component {
        
          constructor(readonly service: ExampleService) {
          }
        }
        ``` 
    2. `ExampleComponent2` which just displays the service's property `name`
        ```typescript
        @Component({
          selector: 'component-scope-example2',
          template: `<p>{{service.name}}</p>`,
          providers: [ExampleService]
        })
        export class Example2Component {
        
          constructor(readonly service: ExampleService) {
          }
        }
        ``` 
2. The `ModuleScopeModule` which uses the **Module Scope** and consists of two similar components.
    The difference is, that the Components don't use the `providers` array. Instead the Service is provided 
    in the Module:
    ```typescript
    @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`:

```html
<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:

![Result in action](https://raw.githubusercontent.com/Nas3nmann/articles/master/Angular/provider-scope/example_served.gif)

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