Services and Dependency Injection
Level: Intermediate
- What services are and why use them
- Dependency injection concept
- Providing services
- Service scope (singleton, instance)
- SMS service example with API calls
Why This Matters
Services = business logic. Separate from components. Services handle API calls, data processing, anything not UI. Dependency Injection = framework provides dependencies automatically.
Service Basics
Service = class with business logic.
// student.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Injectable({
providedIn: 'root'
})
export class StudentService {
private apiUrl = '/api/students';
constructor(private http: HttpClient) {}
getStudents() {
return this.http.get<any[]>(this.apiUrl);
}
getStudent(id: number) {
return this.http.get<any>(`${this.apiUrl}/${id}`);
}
createStudent(student: any) {
return this.http.post<any>(this.apiUrl, student);
}
deleteStudent(id: number) {
return this.http.delete(`${this.apiUrl}/${id}`);
}
}
@Injectable() = mark as service.
providedIn: 'root' = singleton (one instance app-wide).
constructor(private http: HttpClient) = DI injected.
Using Service in Component
// student-list.component.ts
import { Component, OnInit } from '@angular/core';
import { StudentService } from '../services/student.service';
@Component({
selector: 'app-student-list',
templateUrl: './student-list.component.html'
})
export class StudentListComponent implements OnInit {
students: any[] = [];
loading = false;
error: string | null = null;
constructor(private studentService: StudentService) {}
ngOnInit() {
this.loadStudents();
}
loadStudents() {
this.loading = true;
this.studentService.getStudents().subscribe({
next: (data) => {
this.students = data;
this.loading = false;
},
error: (err) => {
this.error = err.message;
this.loading = false;
}
});
}
deleteStudent(id: number) {
this.studentService.deleteStudent(id).subscribe({
next: () => {
this.students = this.students.filter(s => s.id !== id);
},
error: (err) => this.error = err.message
});
}
}
Service injected in constructor(private studentService: StudentService).
Service Scope
// Singleton (one instance app-wide)
@Injectable({
providedIn: 'root'
})
export class SharedService { }
// Scoped to module
@Injectable({
providedIn: StudentModule
})
export class StudentService { }
// Scoped to component (new instance per component)
@Component({
providers: [StudentService]
})
export class StudentListComponent { }
providedIn: 'root' = singleton.
providedIn: Module = scoped to module.
providers: [Service] = scoped to component.
Multiple Services
// teacher.service.ts
@Injectable({ providedIn: 'root' })
export class TeacherService {
private apiUrl = '/api/teachers';
constructor(private http: HttpClient) {}
getTeachers() {
return this.http.get<any[]>(this.apiUrl);
}
}
// exam.service.ts
@Injectable({ providedIn: 'root' })
export class ExamService {
private apiUrl = '/api/exams';
constructor(private http: HttpClient) {}
getExams() {
return this.http.get<any[]>(this.apiUrl);
}
}
// dashboard.component.ts
export class DashboardComponent implements OnInit {
constructor(
private studentService: StudentService,
private teacherService: TeacherService,
private examService: ExamService
) {}
ngOnInit() {
this.studentService.getStudents().subscribe(...);
this.teacherService.getTeachers().subscribe(...);
this.examService.getExams().subscribe(...);
}
}
Multiple services in constructor.
Service Communication
Services can emit events:
// shared.service.ts
import { Subject } from 'rxjs';
@Injectable({ providedIn: 'root' })
export class SharedService {
private studentSelected = new Subject<any>();
studentSelected$ = this.studentSelected.asObservable();
selectStudent(student: any) {
this.studentSelected.next(student);
}
}
// list.component.ts
export class StudentListComponent {
constructor(private shared: SharedService) {}
onStudentClick(student: any) {
this.shared.selectStudent(student);
}
}
// detail.component.ts
export class StudentDetailComponent implements OnInit {
student: any;
constructor(private shared: SharedService) {}
ngOnInit() {
this.shared.studentSelected$.subscribe(student => {
this.student = student;
});
}
}
Subject = event emitter.
Components communicate through service.
Key Takeaways
- Services = business logic, API calls, data
@Injectable()= make it serviceprovidedIn: 'root'= singleton- Dependency Injection = framework injects dependencies
- Constructor injection = request dependencies
- Services separate concerns (UI vs logic)
- Multiple services per component
Services = like repository pattern in .NET. Centralize data access. Components consume service data. Same architecture principles apply.
- Not injecting — Using
new ServiceClass()instead of DI - Wrong scope — Service should be singleton but configured as per-component
- Circular dependencies — Service A needs B, B needs A (breaks DI)
- Not unsubscribing — Memory leaks from subscriptions
Use ChatGPT, Claude, or Copilot to go deeper on Angular Services. Try these prompts:
"Why use service instead of putting logic in component?""What's difference between singleton and per-component service?""How do components communicate through services?""Quiz me on dependency injection"
💡 Tip: After reading this article, paste your own code into AI and ask "What could go wrong here and why?" — fastest way to find edge cases and deepen understanding.