The magic Of Injection Tokens in Angular

George Pappas
4 min readFeb 12, 2022

In this post we are going to see how a powerful feature of dependency injection works and helps our application to be more efficient and follow coding principles. (SRP, DRY)

HardCoded variables are generally a bad practice and of course not scalable.

Let’s say in a file we need to retrieve some data from an endpoint api/products/1. If for some reason this url changes we have to manually change it in every single file that we used this url. Imagine the mess. Of course there is a better way to do it.

Use injection tokens for scalability

As you can see below, we provide a key with the name pokemonListApi and as value we passing an endpoint, so in any constructor we can ask for our pokemonList key like this

constructor(@Inject(pokemonListApi’) private _pokemonListApi: string) {}

Now our _pokemonListApi has the endpoint we provided in the app.module.ts providers array and we can access it from any component in the app.

As you can imagine this approach even though it will work, is not very flexible and scalable because we cant use the same key (‘pokemonListApi’) with a different useValue as it refers to the same hardcoded initialized variable.

So now injection token is come to the rescue.
We can define as many tokens as we want, inject all of them in the providers of app.module.ts and finally ask for them in the any constructor.

constructor(@Inject(‘tokenList’) private pokemonListApi: string) {}

app.module.ts
app.module.ts

Now its token will have it’s own value, that we provided in the useValue property.

2)Use injectionToken to allow access in service function

Last but not least, my favourite part about injection tokens is that follows coding principles and you can control which function you will have access to.

Let’s say for example we have created a service that has 3 functions

userInfo(), 2. initialData(), 3. updateData()

In order to keep the example as simple as possible these functions won’t perform any actions, they just log a string.

authorization.service.ts

Now lets say we want to create an instance for this service in order to ask for it in the constructor of the components.

One other way to create an instance of this service is to put it in the providers array of the component instead of the app.module.(this instance will be destroyed when the component is destroyed but if we put it in the app.module providers it would be a singleton)(Singleton means that this class will have just one instance for the the entire app). This approach will create an instance but as you can see in the picture we can access every function in this service. Maybe we don’t want somebody to mess up with the userInfo function because it contains personal data and we don’t want nobody to access it, even though we have an instance of this service, how can we do that?

Injection token to the rescue again!

First of all we create an interface to give a specific type to our new injection token, and then in the providers array we provide this token with the useClass of our authorization service in order to create an instance of this service.

So now every time we ask for this token it will have the methods of the type we provide. As you can see in the image below, now we can not access the userInfo function but we can access everything else.

Now you now this powerful feature called injection token. Congrats 🍻🍻

That was it guys, thanks for reading.

--

--