inject()
| Since: | Angular 14(2022) |
|---|
The inject() function, introduced in Angular 14, retrieves a dependency from the current injector without declaring it in a constructor. It can be called in field initializers, factory functions, functional route guards, and any code that runs within an injection context. This makes it possible to consume services in standalone functions and simplifies component code by removing the need for constructor parameters.
Syntax
import { inject } from '@angular/core';
import { SomeService } from './some.service';
// In a field initializer (injection context available)
private someService = inject(SomeService);
// Optional injection — returns null if not provided
private optional = inject(SomeService, { optional: true });
Sample Code
Using inject() in a field initializer — no constructor needed.
// greeting.component.ts
import { Component } from '@angular/core';
import { inject } from '@angular/core';
import { LoggerService } from './logger.service';
@Component({
selector: 'app-greeting',
template: `<button (click)="greet()">Greet</button>`,
standalone: true,
})
export class GreetingComponent {
private logger = inject(LoggerService);
greet(): void {
this.logger.log('Hello from GreetingComponent!');
}
}
Extracting a reusable helper function that encapsulates logging logic using inject().
// use-logger.ts
import { inject } from '@angular/core';
import { LoggerService } from './logger.service';
export function useLogger() {
const logger = inject(LoggerService);
return {
log: (message: string) => logger.log(message),
warn: (message: string) => logger.warn(message),
};
}
// dashboard.component.ts
import { Component } from '@angular/core';
import { useLogger } from './use-logger';
@Component({
selector: 'app-dashboard',
template: `<button (click)="onSave()">Save</button>`,
standalone: true,
})
export class DashboardComponent {
private logger = useLogger();
onSave(): void {
this.logger.log('Dashboard saved');
}
}
A functional route guard using inject() — no class boilerplate required.
// auth.guard.ts
import { inject } from '@angular/core';
import { CanActivateFn, Router } from '@angular/router';
import { AuthService } from './auth.service';
export const authGuard: CanActivateFn = () => {
const authService = inject(AuthService);
const router = inject(Router);
if (authService.isLoggedIn()) {
return true;
}
return router.createUrlTree(['/login']);
};
// app.routes.ts
import { Routes } from '@angular/router';
import { authGuard } from './auth.guard';
export const routes: Routes = [
{
path: 'dashboard',
canActivate: [authGuard],
loadComponent: () =>
import('./dashboard/dashboard.component').then(m => m.DashboardComponent),
},
];
Using inject() with { optional: true } to safely handle an optional dependency.
// optional-feature.component.ts
import { Component } from '@angular/core';
import { inject } from '@angular/core';
import { AnalyticsService } from './analytics.service';
@Component({
selector: 'app-optional-feature',
template: `<p>Analytics: {{ analyticsEnabled ? 'on' : 'off' }}</p>`,
standalone: true,
})
export class OptionalFeatureComponent {
private analytics = inject(AnalyticsService, { optional: true });
analyticsEnabled = !!this.analytics;
track(event: string): void {
this.analytics?.track(event);
}
}
Summary
The inject() function, introduced in Angular 14, is an alternative to constructor injection. It must be called within an injection context — during class field initialization, inside the constructor, or in factory functions called during component setup. It cannot be used inside lifecycle hooks like ngOnInit or asynchronous callbacks.
Its main advantages are enabling service consumption in standalone functions (helper functions, functional guards, functional resolvers), and reducing the verbosity of constructor parameter lists. For traditional constructor injection via the @Injectable decorator, see @Injectable.
Common Mistake: Calling inject() outside an injection context
inject() can only be called where Angular's injector is active: in field initializers, constructors, and functions called during component initialization. Calling it in ngOnInit, event handlers, or async callbacks throws an error.
// NG: inject() called in ngOnInit — outside injection context
ngOnInit(): void {
const logger = inject(LoggerService); // Error: inject() must be called from an injection context
}
// OK: inject() in a field initializer
export class MyComponent {
private logger = inject(LoggerService); // correct
}
Common Mistake: Calling inject() inside an async callback
Inside a setTimeout, Promise.then, or any asynchronous callback, the injection context is no longer active. Store the injected dependency in a field first, then use the field inside the callback.
// NG: inject() inside async callback — error
ngOnInit(): void {
setTimeout(() => {
const logger = inject(LoggerService); // Error
logger.log('delayed');
}, 1000);
}
// OK: inject at field level, use in callback
private logger = inject(LoggerService);
ngOnInit(): void {
setTimeout(() => {
this.logger.log('delayed'); // correct
}, 1000);
}
If you find any errors or copyright issues, please contact us.