Services and dependency injection in Angular
What are Services?
A service is a class that encapsulates reusable logic — data fetching, business rules, logging, etc. Services are shared across components via Angular's Dependency Injection (DI) system.
Creating a Service
typescript
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root' // Available application-wide (singleton)
})
export class UserService {
private apiUrl = '/api/users';
constructor(private http: HttpClient) {}
getUsers(): Observable<User[]> {
return this.http.get<User[]>(this.apiUrl);
}
getUserById(id: string): Observable<User> {
return this.http.get<User>(\`\${this.apiUrl}/\${id}\`);
}
createUser(user: Partial<User>): Observable<User> {
return this.http.post<User>(this.apiUrl, user);
}
}Injecting a Service
typescript
@Component({
selector: 'app-user-list',
template: \`
<ul>
<li *ngFor="let user of users">{{ user.name }}</li>
</ul>
\`
})
export class UserListComponent implements OnInit {
users: User[] = [];
// Inject service via constructor
constructor(private userService: UserService) {}
ngOnInit() {
this.userService.getUsers().subscribe(users => {
this.users = users;
});
}
}Modern inject() Function
typescript
import { inject } from '@angular/core';
@Component({ /* ... */ })
export class UserListComponent {
private userService = inject(UserService);
// No constructor needed!
}Providing Services
typescript
// 1. Root level (singleton — most common)
@Injectable({ providedIn: 'root' })
export class AuthService {}
// 2. Component level (new instance per component)
@Component({
providers: [LoggerService] // Each component gets its own instance
})
export class MyComponent {}
// 3. Module level
@NgModule({
providers: [AnalyticsService]
})
export class AnalyticsModule {}Injection Tokens
For non-class dependencies:
typescript
import { InjectionToken } from '@angular/core';
export const API_URL = new InjectionToken<string>('API_URL');
// Provide
@NgModule({
providers: [
{ provide: API_URL, useValue: 'https://api.example.com' }
]
})
// Inject
constructor(@Inject(API_URL) private apiUrl: string) {}
// or
private apiUrl = inject(API_URL);Provider Types
| Provider | Description | Example |
|---|---|---|
useClass | Provide a different class | { provide: Logger, useClass: FileLogger } |
useValue | Provide a static value | { provide: API_URL, useValue: 'https://...' } |
useFactory | Provide via factory function | { provide: Service, useFactory: () => new Service() } |
useExisting | Alias to existing provider | { provide: OldService, useExisting: NewService } |
Important:
Services encapsulate reusable logic and are shared via Dependency Injection. Use @Injectable({ providedIn: 'root' }) for app-wide singletons. Use the modern inject() function over constructor injection when possible. DI makes code testable (mock services in tests) and modular (swap implementations).
Short Answer
Interview readyPremium
A concise answer to help you respond confidently on this topic during an interview.