Skip to main content

Services and Dependency Injection

Level: Intermediate

ℹ️ What You'll Learn
  • 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 service
  • providedIn: 'root' = singleton
  • Dependency Injection = framework injects dependencies
  • Constructor injection = request dependencies
  • Services separate concerns (UI vs logic)
  • Multiple services per component
💡 Backend Developer Tip

Services = like repository pattern in .NET. Centralize data access. Components consume service data. Same architecture principles apply.

⚠️ Service Mistakes
  1. Not injecting — Using new ServiceClass() instead of DI
  2. Wrong scope — Service should be singleton but configured as per-component
  3. Circular dependencies — Service A needs B, B needs A (breaks DI)
  4. Not unsubscribing — Memory leaks from subscriptions
🤖Use AI to Learn Faster

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.

nexcoding.in