Using the Inject Function in Angular 15
Since Angular 14/15, there has been an alternative way to inject dependencies into our Angular applications.
I will show two cases of using the inject function with Angular 14/15.
Inject Dependencies in Functions
Using inject, we can create functions and inject dependencies without adding parameters in the function class.
Example: We create a function that needs the HttpClient to request data.
import {lastValueFrom, map} from "rxjs";
import {inject} from "@angular/core";
import {HttpClient} from "@angular/common/http";
export function getPlayers(): Promise<unknown> {
return lastValueFrom(inject(HttpClient).get('https://www.balldontlie.io/api/v1/players').pipe(
map((response: any) => {
return response.data;
})
))
}
We can use the function in another class in the constructor lifecycle:
constructor() {
getPlayers().then(p => {
this.players = p;
})
}
The inject()
function must be called from an injection context such as a constructor, a factory function, or a field initializer.
Simplify Inheritance Dependencies
Another way to simplify and clean up the constructor in our classes is when we use inheritance. For example, when a class works as a base or superclass for others, like NbaService
, which needs HttpClient
in the constructor.
import {Injectable} from '@angular/core';
import {HttpClient} from "@angular/common/http";
import {map, Observable} from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class NbaService {
constructor(private http: HttpClient) {
}
getPlayers(): Observable<any> {
return this.http.get('https://www.balldontlie.io/api/v1/players').pipe(
map((response: any) => {
return response.data;
})
);
}
}
When we create a new class like NcaaService and extend NbaService, we must provide the constructor dependencies.
import {Injectable} from '@angular/core';
import {NbaService} from "./nba.service";
import {HttpClient} from "@angular/common/http";
import {filter} from 'rxjs';
@Injectable()
export class NcaaService extends NbaService {
constructor(private httpClient: HttpClient) {
super(httpClient);
}
getListPlayers() {
return this.getPlayers().pipe(
filter((p) => p.league === 'NCAA')
)
}
}
What happens if the NbaService constructor changes?
export class NbaService {
constructor(private http: HttpClient, private loader: LoaderService) {
}
....
The NcaaService has to update the constructor and provide a dependency no related with him.
The easy way to solve this is to switch our dependencies from constructor to inject function.
export class NbaService {
http = inject(HttpClient);
loader = inject(LoaderService)
showLoadingMessage() {
this.loader.show();
}
}
The extended classes don't have to provide dependencies anymore. This helps to simplify our code and solve a typical problem when we have to provide dependencies without needing to, only because our base code needs it.
@Injectable()
export class NcaaService extends NbaService {
constructor() {
super();
}
}
Conclusion
Using the inject function in Angular applications can simplify the code and help to solve common problems related to dependency injection. With inject, we can create functions and inject dependencies without adding parameters in the function class, and we can simplify inheritance dependencies.
Subscribe to my newsletter
Read articles from Dany Paredes directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Dany Paredes
Dany Paredes
I'm passionate about front-end development, specializing in building UI libraries and working with technologies like Angular, NgRx, Accessibility, and micro-frontends. In my free time, I enjoy writing content for the Google Dev Library, This Is Angular Community, Kendo UI, and sharing insights here.