Dependency Injection
Esta página aún no está disponible en tu idioma.
What is Dependency Injection?
Section titled “What is Dependency Injection?”Dependency Injection (DI) is a design pattern where a class receives its dependencies from external sources rather than creating them itself.
Without DI (❌ Bad)
Section titled “Without DI (❌ Bad)”export class UserComponent { private userService = new UserService(); // Creates dependency internally
loadUsers() { this.userService.getUsers().subscribe(users => { console.log(users); }); }}Problems:
- Hard to test (can’t mock
UserService) - Tightly coupled to
UserService - If
UserServicerequires dependencies,UserComponentmust know about them
With DI (✅ Good)
Section titled “With DI (✅ Good)”export class UserComponent { constructor(private userService: UserService) {} // Dependency injected
loadUsers() { this.userService.getUsers().subscribe(users => { console.log(users); }); }}Benefits:
- Easy to test (can inject mock service)
- Loosely coupled
- Angular manages the service lifecycle
Constructor Injection vs inject() Function
Section titled “Constructor Injection vs inject() Function”Angular provides two ways to inject dependencies:
Constructor Injection (Traditional)
Section titled “Constructor Injection (Traditional)”import { Component } from '@angular/core';import { UserService } from './user.service';
@Component({ selector: 'app-user', template: '<div>{{ users | json }}</div>'})export class UserComponent { users: User[] = [];
constructor(private userService: UserService) { this.userService.getUsers().subscribe(users => { this.users = users; }); }}export class UserComponent { constructor( private userService: UserService, private notificationService: NotificationService, private router: Router, private route: ActivatedRoute ) {}}inject() Function (Modern - Angular 14+)
Section titled “inject() Function (Modern - Angular 14+)”import { Component, inject } from '@angular/core';import { UserService } from './user.service';
@Component({ selector: 'app-user', template: '<div>{{ users | json }}</div>'})export class UserComponent { users: User[] = []; private userService = inject(UserService);
ngOnInit() { this.userService.getUsers().subscribe(users => { this.users = users; }); }}export class UserComponent { private userService = inject(UserService); private notificationService = inject(NotificationService); private router = inject(Router); private route = inject(ActivatedRoute);}Comparison
Section titled “Comparison”| Aspect | Constructor | inject() |
|---|---|---|
| Angular version | All versions | 14+ |
| Syntax | Less boilerplate | More explicit |
| Readability | Parameter list can get long | Clear and organized |
| Optional injection | ❌ Requires Optional() | ✅ Built-in support |
| Flexibility | Less flexible | More flexible |
Providing Dependencies
Section titled “Providing Dependencies”Method 1: providedIn: ‘root’ (Recommended)
Section titled “Method 1: providedIn: ‘root’ (Recommended)”import { Injectable } from '@angular/core';
@Injectable({ providedIn: 'root' })export class UserService { // This service is a singleton available app-wide}Benefits:
- Singleton instance across the entire app
- Tree-shakeable (unused services removed in production build)
- Simplest approach
- Best for services needed throughout the app
Method 2: providedIn: ‘platform’
Section titled “Method 2: providedIn: ‘platform’”@Injectable({ providedIn: 'platform' })export class LoggingService { // Shared across all app instances}Use when: Service must be shared across multiple Angular applications on the same page
Method 3: Feature Module Providers
Section titled “Method 3: Feature Module Providers”@NgModule({ providers: [UserService]})export class UserModule {}Use when: Service is only needed within a specific feature module
Method 4: Component Providers
Section titled “Method 4: Component Providers”@Component({ selector: 'app-user', providers: [UserService]})export class UserComponent { // Each component instance gets its own UserService}Use when: Service must be unique per component instance
Optional Dependencies
Section titled “Optional Dependencies”With Constructor Injection
Section titled “With Constructor Injection”import { Component, Optional } from '@angular/core';
export class UserComponent { constructor(@Optional() private userService?: UserService) { if (this.userService) { // Use service } }}With inject()
Section titled “With inject()”import { Component, inject } from '@angular/core';
export class UserComponent { private userService = inject(UserService, { optional: true });
ngOnInit() { if (this.userService) { // Use service } }}Practical Examples
Section titled “Practical Examples”User Service with API
Section titled “User Service with API”import { Injectable, inject } from '@angular/core';import { HttpClient } from '@angular/common/http';import { Observable } from 'rxjs';
@Injectable({ providedIn: 'root' })export class UserService { private http = inject(HttpClient); private apiUrl = '/api/users';
getUsers(): Observable<User[]> { return this.http.get<User[]>(this.apiUrl); }
getUserById(id: string): Observable<User> { return this.http.get<User>(`${this.apiUrl}/${id}`); }}Component Using Injected Service
Section titled “Component Using Injected Service”import { Component, inject, OnInit } from '@angular/core';import { UserService } from './user.service';
@Component({ selector: 'app-user-list', template: ` <div *ngFor="let user of users"> <h3>{{ user.name }}</h3> <p>{{ user.email }}</p> </div> `})export class UserListComponent implements OnInit { users: User[] = []; private userService = inject(UserService);
ngOnInit() { this.userService.getUsers().subscribe(users => { this.users = users; }); }}Multiple Injected Dependencies
Section titled “Multiple Injected Dependencies”import { Component, inject } from '@angular/core';import { UserService } from './user.service';import { NotificationService } from './notification.service';import { Router } from '@angular/router';
@Component({ selector: 'app-user-manager'})export class UserManagerComponent { private userService = inject(UserService); private notificationService = inject(NotificationService); private router = inject(Router);
deleteUser(userId: string) { this.userService.deleteUser(userId).subscribe({ next: () => { this.notificationService.showSuccess('User deleted'); this.router.navigate(['/users']); }, error: (err) => { this.notificationService.showError('Failed to delete user'); } }); }}Dependency Injection Checklist
Section titled “Dependency Injection Checklist”- Services use
@Injectable({ providedIn: 'root' }) - Components inject services via
inject()or constructor - No manual service instantiation with
new - Optional dependencies marked with
@Optional()or{ optional: true } - Services are singletons where appropriate
- No circular dependencies between services
- Service dependencies documented in JSDoc
Best Practices
Section titled “Best Practices”✅ Always use DI for services and dependencies ✅ Use providedIn: ‘root’ for app-wide services ✅ Keep services focused on a single responsibility ✅ Test with mock services injected via DI ✅ Use inject() in new code (Angular 14+) ✅ Provide in the narrowest scope needed ✅ Document required dependencies in service JSDoc