inject() Function (v14)
📚 What is inject() Function?
inject() is a functional way to access dependency injection, introduced in Angular 14:
- Functional approach: No constructor needed
- Works everywhere: Components, services, guards, pipes, directives
- Field initializers: Can be used in class field declarations
- Factory functions: Enables functional patterns and composition
- Must be in injection context: Constructor, field initializer, or factory function
🎯 Interview Questions
- Q1: What is the advantage of inject() over constructor injection?
- A: Can be used outside constructors (field initializers, factory functions), supports functional patterns, cleaner syntax for many dependencies.
- Q2: Where can you use inject()?
- A: In injection context: constructor, field initializer, factory function called from injection context, or runInInjectionContext().
- Q3: What is runInInjectionContext()?
- A: Function that allows running code in an injection context outside of normal DI flow, useful for dynamic injection.
- Q4: How do you inject optional dependencies with inject()?
- A: Use inject(Service, { optional: true }) to return undefined if not found instead of throwing error.
🔧 Live Demo - inject() Usage
Data from DataService (using inject):
- Item 1
- Item 2
- Item 3
Injected Config (InjectionToken):
Base URL: https://api.example.com
Timeout: 5000ms
🔄 Constructor vs inject() Comparison
Constructor Injection (Old)
constructor(
private dataService: DataService,
private logger: LoggerService,
@Optional() private config: Config
) {}inject() Function (New) ✅
private dataService = inject(DataService);
private logger = inject(LoggerService);
private config = inject(Config, { optional: true });💻 inject() Function Examples
import { inject, InjectionToken } from '@angular/core';
// ===== Basic inject() usage =====
@Component({...})
export class MyComponent {
// Field initializer - cleaner syntax!
private readonly http = inject(HttpClient);
private readonly router = inject(Router);
private readonly service = inject(MyService);
// No constructor needed for simple cases!
}
// ===== inject() in Services =====
@Injectable({ providedIn: 'root' })
export class DataService {
private readonly http = inject(HttpClient);
private readonly logger = inject(LoggerService);
fetchData() {
this.logger.log('Fetching...');
return this.http.get('/api/data');
}
}
// ===== Optional and Self/SkipSelf =====
private optional = inject(Service, { optional: true }); // undefined if not found
private self = inject(Service, { self: true }); // Only this injector
private skipSelf = inject(Service, { skipSelf: true }); // Parent injector only
// ===== InjectionToken with inject() =====
const API_URL = new InjectionToken<string>('API_URL');
// In component
private apiUrl = inject(API_URL);
// ===== Factory function pattern =====
function createDataLoader() {
const http = inject(HttpClient);
const baseUrl = inject(API_URL);
return {
load: (id: string) => http.get(`${baseUrl}/items/${id}`)
};
}
@Component({...})
export class MyComponent {
private loader = createDataLoader(); // Works!
}
// ===== Functional Guards with inject() =====
export const authGuard = () => {
const auth = inject(AuthService);
const router = inject(Router);
if (auth.isAuthenticated()) {
return true;
}
return router.parseUrl('/login');
};