Angular Services and Dependency Injection
Fast recall
Quick revision
Core answer
Whether you understand a service as shared logic and DI as Angular constructing and injecting it into components — and that providedIn: 'root' means singleton.
Putting data-fetching or business logic directly in a component instead of a service (untestable, duplicated).
A service is @Injectable shared logic; DI injects it into components via constructor; providedIn:'root' = singleton. Components stay lean; services are mockable.
Interview-ready guide
Interview answer
A service in Angular is a TypeScript class decorated with Injectable that holds shared logic or data — fetching from an API, holding cart state, or enforcing business rules — that components shouldn't duplicate.
Dependency injection is how Angular hands a component the services it needs. You register a service as a provider, and when a component's constructor asks for it, Angular creates or reuses the instance and injects it automatically. Setting providedIn root makes a service a singleton across the whole app, so every component gets the same instance and shared state.
DI lets components stay lean — they delegate to services — and makes services mockable in tests, which is the foundation of maintainable Angular code. The common mistakes are putting fetch or business logic directly in a component instead of a service, forgetting the Injectable decorator, or creating a service with new instead of letting Angular inject it, which loses the singleton and testability.
Angular Services and Dependency Injection
Direct Answer
A service is a TypeScript class (decorated with @Injectable) that holds shared logic or data (fetching, state, business rules) that components shouldn't duplicate. Dependency injection (DI) is Angular's mechanism for giving a component the services it needs: you declare a service as a provider, and when a component's constructor asks for it, Angular creates (or reuses) the instance and injects it. providedIn: 'root' makes a service a singleton app-wide. DI makes components lean (they delegate to services) and makes services mockable in tests — the core of maintainable Angular code.
Code Example
// (1) SERVICE: @Injectable shared logic. providedIn:'root' = one instance app-wide.
@Injectable({ providedIn: 'root' })
export class CartService {
private items: string[] = [];
add(item: string) { this.items.push(item); }
get count() { return this.items.length; }
}
// (2) COMPONENT asks for the service in its constructor; Angular INJECTS it.
@Component({ selector: 'app-cart', template: `<button (click)="add()">Add ({{count}})</button>` })
export class CartComponent {
constructor(private cart: CartService) {} // ANGULAR injects it
count = 0; add() { this.cart.add('item'); this.count = this.cart.count; }
}
// Because CartService is providedIn:'root', every component gets the SAME
// instance -> shared cart state. In a test, you pass a mock instead.
Common Mistakes & Pitfalls
- Putting fetch/business logic directly in a component instead of a service — duplicated and untestable.
- Forgetting @Injectable on a service, or not setting providedIn so it can't be injected.
- Creating a service instance with new instead of letting Angular inject it (loses the singleton/DI).
Check your understanding
Answer these without looking back at the article.
- What is a service in Angular, and what decorator marks it?
- How does dependency injection hand a service to a component (constructor)?
- What does providedIn:'root' mean (singleton), and why is it the default?
- Why put logic in a service rather than a component (testability, reuse)?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.