Dependency Injection
Basic Dependency Injection, singleton pattern and reuseable
Dependency Injection (DI) in Angular
What is Dependency Injection?
Dependency Injection (DI) is a design pattern where classes receive their dependencies from an external source rather than creating them internally. In Angular, the DI system provides and manages dependencies across your application.
Basic Service Example
Here’s a simple service that manages a list of Fresher names:
// fresher.service.ts
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root' // Makes this a singleton service
})
export class FresherService {
private freshers: string[] = [
'John Doe',
'Jane Smith',
'Mike Johnson'
];
getFreshers(): string[] {
return this.freshers;
}
addFresher(name: string) {
this.freshers.push(name);
}
}
Using the Service in Components
// fresher-list.component.ts
import { Component, OnInit } from '@angular/core';
import { FresherService } from './fresher.service';
@Component({
selector: 'app-fresher-list',
template: `
<h2>Fresher List</h2>
<ul>
<li *ngFor="let fresher of freshers">
{{ fresher }}
</li>
</ul>
<button (click)="addNewFresher()">Add Fresher</button>
`
})
export class FresherListComponent implements OnInit {
freshers: string[] = [];
constructor(private fresherService: FresherService) {}
ngOnInit() {
this.freshers = this.fresherService.getFreshers();
}
addNewFresher() {
this.fresherService.addFresher('New Fresher');
this.freshers = this.fresherService.getFreshers();
}
}
Service with HTTP Example
Here’s a more realistic example using HttpClient:
// fresher.interface.ts
interface Fresher {
id: number;
name: string;
email: string;
}
// fresher.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class FresherService {
private apiUrl = 'api/freshers';
constructor(private http: HttpClient) {}
getFreshers(): Observable<Fresher[]> {
return this.http.get<Fresher[]>(this.apiUrl);
}
addFresher(fresher: Fresher): Observable<Fresher> {
return this.http.post<Fresher>(this.apiUrl, fresher);
}
}
DI Providers
There are different ways to provide services in Angular:
- Root-level Provider (Singleton):
@Injectable({
providedIn: 'root'
})
- Module-level Provider:
@NgModule({
providers: [FresherService]
})
- Component-level Provider:
@Component({
providers: [FresherService] // New instance for this component
})
Best Practices
- Use providedIn: ‘root’ for singleton services
@Injectable({
providedIn: 'root'
})
- Implement OnDestroy for cleanup:
export class MyService implements OnDestroy {
ngOnDestroy() {
// Cleanup code
}
}
- Use Interfaces for better type safety:
interface ServiceConfig {
apiUrl: string;
timeout: number;
}
@Injectable({providedIn: 'root'})
class MyService {
constructor(@Inject('CONFIG') private config: ServiceConfig) {}
}
- Lazy Loading with feature modules:
@Injectable({
providedIn: 'any' // New instance per lazy-loaded module
})
Common Use Cases
- Data Services: Managing application data
@Injectable({providedIn: 'root'})
export class DataService {
private data: any[] = [];
getData() { return this.data; }
addData(item: any) { this.data.push(item); }
}
- State Management: Managing application state
@Injectable({providedIn: 'root'})
export class StateService {
private state = new BehaviorSubject<any>(initialState);
state$ = this.state.asObservable();
updateState(newState: any) {
this.state.next(newState);
}
}
- Utility Services: Shared functionality
@Injectable({providedIn: 'root'})
export class UtilityService {
formatDate(date: Date): string {
return date.toLocaleDateString();
}
generateId(): string {
return Math.random().toString(36).substr(2, 9);
}
}
Testing with DI
describe('FresherComponent', () => {
let component: FresherComponent;
let service: FresherService;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [FresherComponent],
providers: [FresherService]
});
component = TestBed.createComponent(FresherComponent).componentInstance;
service = TestBed.inject(FresherService);
});
it('should load freshers', () => {
const mockFreshers = ['John', 'Jane'];
spyOn(service, 'getFreshers').and.returnValue(mockFreshers);
component.ngOnInit();
expect(component.freshers).toEqual(mockFreshers);
});
});
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.