Angular Injection Token - When to Use It?
In this post you will learn what is Angular injection token and how you can use it.
Typically inside Angular we are working a lot with injection of our services. Here I already created a UsersService
.
@Injectable()
export class UsersService {
constructor(private http: HttpClient) {}
getUsers() {
return this.http.get('http://localhost:3004/users');
}
}
Let's inject it like we normally do in any application.
export class AppComponent {
constructor(private usersService: UsersService) {
console.log('usersService', usersService)
}
}
And we need to register it inside our module.
@NgModule({
...
providers: [UsersService]
})
export class AppModule {}
Inside browser we can see that it is available for us.
But the code that we wrote here is just a sugar. The provided value is actually something more. For Angular it look like this.
provides: [{provide: UsersService, useClass: UsersService}]
It works in exactly the same way as simple [UsersService]
is just a sugar.
Except of useClass
we have useValue
, useFactory
and others for different cases.
Identifiers
But it is important to understand what is provide
and what is useClass
. useClass
is obvious as this is a class that we want to register here.
provide
is not just used like a class but as a unique identifier. We could just write a string there.
provides: [{provide: 'USERS_SERVICE', useClass: UsersService}]
Here we defined a provider by this string. But it won't work like this as we must inject it differently.
export class AppComponent {
constructor(@Inject('USERS_SERVICE') private usersService: UsersService) {
console.log('usersService', usersService)
}
}
Here we did it through Inject
and providing the same string to find our provider. As you can see in browser it works exactly like before.
This is nothing more but just a unique identifier because all things that we inject must be unique for the injector.
Injecting config
And actually this @Inject
plays really nicely when you need to pass a config inside. Let's create an interface for our config.
export interface UsersServiceConfigInterface {
apiUrl: string;
}
@NgModule({
...
providers: [
...
{
provide: 'USERS_SERVICE_CONFIG',
useValue: { apiUrl: 'http://localhost:3004/users' },
},
],
})
Here we created an interface and registered a config as a provider. Now at any place inside our module we can inject it.
export class AppComponent {
constructor(
@Inject('USERS_SERVICE') private usersService: UsersService,
@Inject('USERS_SERVICE_CONFIG') private config: UsersServiceConfigInterface
) {
console.log('usersService', usersService)
}
}
Injection token
Which actually brings us to injection tokens inside Angular. Previously we used just string but they must be unique. But obviously strings are not really unique and we can easily to a typo and then it won't work. This is why we have injection tokens.
This is exactly what we can use as a unique identifier instead of our strings.
export const USERS_SERVICE_TOKEN = new InjectionToken<UsersService>('');
export const USERS_SERVICE_CONFIG_TOKEN = new InjectionToken<UsersServiceConfigInterface>(
''
);
@NgModule({
...
providers: [
{provide: USERS_SERVICE_TOKEN, useClass: UsersService},
{
provide: USERS_SERVICE_CONFIG_TOKEN,
useValue: { apiUrl: 'http://localhost:3004/users' },
},
],
})
Here in our module we created 2 injection tokens. Inside we specified what will be our data type. But here you must be wondering why we provided inside an empty string if it must be a unique value. This string is just a description of the token and nothing more. We can provide an empty string inside and it will still be unique.
The only thing that we need to do now is to change our string on the service to injection tokens.
export class AppComponent {
constructor(
@Inject(USERS_SERVICE_TOKEN) private usersService: UsersService,
@Inject(USERS_SERVICE_CONFIG_TOKEN) private config: UsersServiceConfigInterface
) {
console.log('usersService', usersService)
}
}
And our code works like before.
So as you can see we need injection tokens in order to generate a unique identifier for our providers registration inside Angular.
Want to conquer your next JavaScript interview? Download my FREE PDF - Pass Your JS Interview with Confidence and start preparing for success today!
📚 Source code of what we've done