On this page
Services and Dependency Injection
Services hold reusable business logic, API calls, and shared state. Dependency injection (DI) lets Angular create and deliver those services wherever they are needed.
Creating a Service
ng generate service services/user
import { Injectable } from '@angular/core';
export interface User {
id: number;
name: string;
email: string;
}
@Injectable({
providedIn: 'root' // Singleton available app-wide
})
export class UserService {
private users: User[] = [
{ id: 1, name: 'Alice', email: '[email protected]' },
{ id: 2, name: 'Bob', email: '[email protected]' }
];
getUsers(): User[] {
return this.users;
}
getUserById(id: number): User | undefined {
return this.users.find(u => u.id === id);
}
addUser(user: Omit<User, 'id'>): User {
const newUser = { ...user, id: Date.now() };
this.users.push(newUser);
return newUser;
}
}
providedIn: 'root' registers the service with the root injector — one instance for the entire app.
Injecting a Service
Use the inject() function or constructor injection:
import { Component, inject } from '@angular/core';
import { UserService } from '../services/user.service';
@Component({
selector: 'app-user-list',
standalone: true,
template: `
@for (user of users; track user.id) {
<p>{{ user.name }} — {{ user.email }}</p>
}
`
})
export class UserListComponent {
private userService = inject(UserService);
users = this.userService.getUsers();
}
Sharing State Between Components
Services act as a lightweight store when multiple components need the same data:
@Injectable({ providedIn: 'root' })
export class CartService {
private items: string[] = [];
addItem(item: string) {
this.items.push(item);
}
getItems(): string[] {
return [...this.items];
}
get count(): number {
return this.items.length;
}
}
@Component({
selector: 'app-cart-badge',
standalone: true,
template: `<span>Cart ({{ cart.count }})</span>`
})
export class CartBadgeComponent {
cart = inject(CartService);
}
Provider Scopes
| Registration | Scope |
|---|---|
providedIn: 'root' |
App-wide singleton |
Component providers: [MyService] |
New instance per component |
Route providers: [MyService] |
New instance per route |
Component-scoped example:
@Component({
selector: 'app-editor',
standalone: true,
providers: [EditorStateService],
template: `<textarea></textarea>`
})
export class EditorComponent {}
Each app-editor instance gets its own EditorStateService.
HTTP Services
Services commonly wrap HttpClient (covered in the HTTP chapter):
@Injectable({ providedIn: 'root' })
export class ApiService {
private http = inject(HttpClient);
private baseUrl = '/api';
getPosts() {
return this.http.get<Post[]>(`${this.baseUrl}/posts`);
}
}
Use services to keep components thin — components handle presentation; services handle data and logic.