I'm doing some self exploration into Angular Providers, and created a post about how to create an Angular provider and how it is automatically created at the root level using providedIn metadata.

Sometimes you don't want to create a provider at a root, such as one required for a single component or a single screen in your app. In that case you may want to treat the component differently.

Create the Provider

The Angular CLI allows us to create a provider pretty easily:

view plain print about
1ng generate service

You'll see something like this:

Let's look at the code:

view plain print about
1import { Injectable } from '@angular/core';
2
3@Injectable({
4 providedIn: 'root'
5})
6export class TestService {
7
8 constructor() { }
9}

For this purpose, we want to automatically remove the Injectable metadata config object:

view plain print about
1import { Injectable } from '@angular/core';
2
3@Injectable()
4export class TestService {
5
6 constructor() { }
7}

The provideIn root will automatically add the provider as part of your application and define it in the root module. But, here we want more granular control over how it is created. By removing that providedIn config object the provider will need to be manually set up.

Setup the Provider

To manually set up a provider we need to list it in the providers array of a module, or component. I believe most Angular entities support providers, but it is unusual I use them for things outside of modules or components. Here is the provider being set up in the main app module:

view plain print about
1@NgModule({
2 declarations: [AppComponent, Comp1Component],
3 imports: [BrowserModule],
4 providers: [TestService],
5 bootstrap: [AppComponent]
6})
7export class AppModule { }

The NgModule metadata has a providers array, and we list out each provider as part of the array, referring to the class.

Of course, if you're going to do this ya might as well use the providedIn metadata.

Here is how we may add it a component:

view plain print about
1@Component({
2 selector: 'app-comp1',
3 templateUrl: './comp1.component.html',
4 styleUrls: ['./comp1.component.css'],
5 providers: [TestService]
6})
7export class Comp1Component implements OnInit {
8
9 constructor(public testService: TestService) { }
10
11 ngOnInit(): void {
12 }
13
14}

In this case, the provider is set up at the component level. This provider will be accessible to this component and all of this component's children. It will not be accessible to parent components, or components that exist in a parallel hierarchy. This is how you create a provider strictly for one screen without sharing it everywhere.

Using a Provider

From here, using the provider is no different than one injected into the main app using the providedIn config.

First, let's add a piece of data to the service:

view plain print about
1export class TestService {
2 myData = 'test data';
3
4 constructor() { }
5}

I cut out the imports and metadata to make the code sample shorter.

Now you can just like the provider as part of the constructor to the relevant object you need, like this:

view plain print about
1constructor(public testService: TestService ) {
2 console.log(this.testService.myData);
3 }

I already demoed this in the component sample above.

By listing the service name as an Argument to the constructor of one of these Angular classes; Angular will automatically know to inject this singleton instance whenever the new component is created. Be sure to list the constructor argument as public, or else Angular will not know to inject the singleton.

Once Angular injects it as a Singleton, then an instance variable is created named after the constructor object that can be used throughout the class code as needed. You can even reference it within a template.

For this sample, I Dumped the value inside to the console. It is a super simple, and completely boring use case, but works as a proof of principle.