[Angular] Provider & InjectionToken

kelly woo
3 min readMar 14, 2021
Photo by James Pond on Unsplash

Dependency Injection is popular pattern in programming, creates value or instance outside of the class and inject it into another object to use that.
When you see the Module of Angular, you can see how hard they tried to make applying DI simple by declaring metadata.

@NgModule({   
declarations: [AppComponent],
imports: [BrowserModule],
providers: [AppAPIService],
bootstrap: [AppComponent]
})
export class AppModule {}

An instance created upon angular concepts(like component, module, service), they look into the dependencies at their level, but if nothing found, it crawls back to the root and use it(like prototype chaining).

This means that you can always inherit the dependencies from parents and be able to shadow any dependencies by redeclaring.

On NgModule code above, To declare AppApiService as a provider, we append the class into an array of providers.
That code is saying that we’re gonna use AppApiService instance for AppApiService provide(token). They don’t need to be identical, token(provide) can be anything but it better be unique.

The form we used like a habit is the short form of classProvider.

ClassProvider(useClass)

providers: [{provide: AppAPIService, useClass: AppAPIService}],

useClass creates new instance, providing AppApiService at RootComponent and at ChildComponent means we use AppApiService instance for AppApiService provide, they do not share reference, not the same instance.

ExistingProvider(useExisting)

providers: [{provide: AppAPIService, useExisting: AppAPIService}],

It is mostly same as class Provider at using class, but different that metadata does not create new instance, instead it uses the existing one.

Why do we need to use existing, you might wonder like me, but there’s many cases we actually use this to cut circular dependencies, get specific classes used, and with forwardRef, we can use for common tokens like NG_VALUE_ACCESSOR (see more)

@Component({
...,
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => SelectComponent),
multi: true,
// NG_VALUE_ACCESSOR token can have various values,
// multi should be set true
}],
...})
export class SelectComponent implements ControlValueAccessor{}

ValueProvider(UseValue)

providers: [{provide: MOMENT_TOKEN, useValue: moment],

This is one of the popular provider, injecting outer value or references.
There are many libraries that comes in handy, and if you’d like to use as the injection this provider is what you are looking for. You can put any dependencies declared on global into local variable, this is good for test.

And also angular provide FactoryProvider.

FactoryProvider(UseFactory)

providers: [{
provide: AppAPIService,
useFactory: (apiUrlService: ApiUrlService) => {
return new AppApiService(apiUrlService)
},
deps: [ApiUrlService]
],

classes that queued in deps are by useExisting, you can offer different instance of deps.

These are pretty basic of provider interface and it is useful how to control the dependencies, especially app is rapidly changes.

InjectionToken

Last thing is about InjectionToken, earlier it is said that providers take anything unique as provide(token), but it makes hard to keep the track of that token, so angular provide generator for the token to keep it unique.

export const MOMENT_TOKEN = new InjectionToken('do not use free variable of moment');
// in component get the dependency you can not use type straight,
should use @Inject annotation
@Component({...})
export class DateComponent {
constructor(@Inject(MOMENT_TOKEN) private moment: Moment){
}
}

There are more depth and delicate logics that I can not understand yet that I’m slowly going, if any errors are seen on the article, please don’t hesitate to update me.

Thank you for reading 😀

--

--