Angular Shared Services

Learn Angular Shared Services with Dependency Injection, RxJS BehaviorSubject, component communication, state management, architecture diagrams, enterprise examples, best practices, and interview questions.

A Shared Service is an Angular service used to share data, business logic, and application state across multiple components.

Instead of passing data through multiple parent-child relationships using @Input() and @Output(), components can communicate through a shared singleton service.

Shared Services are one of the most widely used design patterns in enterprise Angular applications.

Common use cases include:

  • User Login State
  • Shopping Cart
  • Theme Management
  • Notifications
  • Search Filters
  • Language Settings
  • Dashboard Refresh
  • Real-Time Data

Understanding Shared Services is an important Angular interview topic for Senior Developers, Tech Leads, and Architects.


Table of Contents

  • What are Shared Services?
  • Why Shared Services?
  • How Shared Services Work
  • Dependency Injection
  • Sharing State
  • RxJS BehaviorSubject
  • Subject vs BehaviorSubject
  • Component Communication
  • Enterprise Example
  • Performance Best Practices
  • Common Mistakes
  • Top 10 Interview Questions
  • Summary

What is a Shared Service?

A Shared Service is a singleton Angular service that multiple components can access through Angular's Dependency Injection (DI) system.

Example

@Injectable({
  providedIn: 'root'
})
export class ThemeService {

  currentTheme = 'light';

}

All components receive the same service instance.


Shared Service Architecture

flowchart LR

RootInjector

RootInjector --> ThemeService

ThemeService --> HeaderComponent

ThemeService --> SidebarComponent

ThemeService --> DashboardComponent

ThemeService --> FooterComponent

Why Use Shared Services?

Without Shared Service

Parent

↓

Child A

↓

Child B

↓

Child C

↓

Child D

Data must be passed through multiple levels.

Problems

  • Deep component hierarchy
  • Too many Inputs
  • Too many Outputs
  • Difficult maintenance
  • Tight coupling

With Shared Service

Header

↓

ThemeService

↑

Sidebar

↑

Dashboard

↑

Footer

Benefits

  • Loose coupling
  • Better scalability
  • Shared state
  • Easier maintenance
  • Cleaner architecture

Component Communication

flowchart TD

Header

Header --> SharedService

Sidebar --> SharedService

Dashboard --> SharedService

Footer --> SharedService

SharedService --> SharedState

Creating a Shared Service

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class UserService {

  userName = 'Guest';

}

Angular creates one shared instance for the Root Environment Injector.


Dependency Injection Flow

sequenceDiagram

participant Header

participant Dashboard

participant Injector

participant UserService

Header->>Injector: Request UserService

Injector->>UserService: Create Instance

UserService-->>Header: Shared Instance

Dashboard->>Injector: Request UserService

Injector-->>Dashboard: Same Instance

Sharing Data

Service

@Injectable({
  providedIn: 'root'
})
export class CounterService {

  count = 0;

  increment() {
    this.count++;
  }

}

Component A

constructor(
  public counter: CounterService
) {}

increase() {
  this.counter.increment();
}

Component B

constructor(
  public counter: CounterService
) {}

Both components share the same counter value.


Shared State Flow

flowchart TD

ComponentA

ComponentA --> CounterService

CounterService --> SharedCount

SharedCount --> ComponentB

SharedCount --> ComponentC

Using RxJS BehaviorSubject

The recommended approach for shared reactive state is BehaviorSubject.

import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class UserStateService {

  private currentUser =
    new BehaviorSubject<string>('Guest');

  currentUser$ =
    this.currentUser.asObservable();

  updateUser(name: string) {
    this.currentUser.next(name);
  }

}

Consumer

user$ =
this.userState.currentUser$;

Update

this.userState.updateUser('Venu');

BehaviorSubject Architecture

flowchart LR

ComponentA

ComponentA --> BehaviorSubject

BehaviorSubject --> ComponentB

BehaviorSubject --> ComponentC

BehaviorSubject --> ComponentD

Subject vs BehaviorSubject

Subject BehaviorSubject
No initial value Requires initial value
New subscribers receive future values only New subscribers immediately receive the latest value
Good for events Excellent for shared state
No current value Stores the current value

Shared Service with HTTP

@Injectable({
  providedIn: 'root'
})
export class EmployeeService {

  constructor(
    private http: HttpClient
  ) {}

  getEmployees() {
    return this.http.get<Employee[]>(
      '/api/employees'
    );
  }

}

Components consume the same service instead of duplicating HTTP calls.


HTTP Service Flow

flowchart LR

EmployeeComponent

EmployeeComponent --> EmployeeService

EmployeeService --> HttpClient

HttpClient --> RESTAPI

RESTAPI --> Database

Shared Service for Notifications

@Injectable({
  providedIn: 'root'
})
export class NotificationService {

  private message =
    new BehaviorSubject('');

  message$ =
    this.message.asObservable();

  notify(text: string) {
    this.message.next(text);
  }

}

Any component can publish or subscribe to notifications.


Notification Architecture

flowchart TD

PaymentComponent

PaymentComponent --> NotificationService

NotificationService --> BehaviorSubject

BehaviorSubject --> Header

BehaviorSubject --> Dashboard

BehaviorSubject --> Footer

Shared Service for Theme

@Injectable({
  providedIn: 'root'
})
export class ThemeService {

  private theme =
    new BehaviorSubject('light');

  theme$ =
    this.theme.asObservable();

  setTheme(theme: string) {
    this.theme.next(theme);
  }

}

Every component updates automatically when the theme changes.


Theme Flow

flowchart TD

ThemeService

ThemeService --> BehaviorSubject

BehaviorSubject --> Header

BehaviorSubject --> Sidebar

BehaviorSubject --> Dashboard

BehaviorSubject --> Footer

Enterprise Banking Example

An online banking application contains:

Components

  • Dashboard
  • Accounts
  • Transfers
  • Investments
  • Notifications

Shared Services

  • UserSessionService
  • NotificationService
  • ThemeService
  • AccountStateService
  • AuthenticationService

Architecture

flowchart TD

Dashboard

Dashboard --> AccountStateService

Transfers --> AccountStateService

Header --> NotificationService

Sidebar --> ThemeService

NotificationService --> BehaviorSubject

AccountStateService --> BankingAPI

AuthenticationService --> IdentityProvider

Benefits

  • Shared login state
  • Shared account information
  • Centralized notifications
  • Consistent application theme
  • Better scalability

Shared Service vs @Input/@Output

Shared Service @Input/@Output
Works across unrelated components Parent-child communication only
Global/shared state Local communication
RxJS support Event binding
Scalable Best for simple hierarchies
Singleton Component-specific

Performance Best Practices

Practice Benefit
Use providedIn: 'root' Singleton instance
Prefer BehaviorSubject for state Reactive updates
Expose Observables Encapsulation
Keep services focused Easier maintenance
Avoid duplicate providers Prevent multiple instances
Complete subscriptions where needed Prevent leaks

Common Mistakes

Using Shared Services for Local Component State

Component-specific form or dialog state should generally remain inside the component.


Exposing Subjects Directly

Avoid

public user =
new BehaviorSubject('');

Prefer

private user =
new BehaviorSubject('');

user$ =
this.user.asObservable();

Only the service should call next().


Registering the Service Multiple Times

Avoid registering the same service in component providers when it is already provided in the root injector.


Storing Too Much State

Keep shared services focused.

Split responsibilities into multiple services.


Ignoring Subscription Cleanup

When subscribing manually, unsubscribe appropriately or use the async pipe where practical.


Best Practices

  • Use providedIn: 'root'.
  • Keep shared services focused.
  • Prefer BehaviorSubject for shared state.
  • Expose Observables, not Subjects.
  • Keep components presentation-focused.
  • Use Dependency Injection.
  • Avoid duplicate provider registrations.
  • Unit test service logic independently.

Advantages

Feature Benefit
Shared State Multiple components
Singleton One instance
Loose Coupling Cleaner architecture
RxJS Reactive communication
Testability Easy mocking
Scalability Enterprise-ready

Top 10 Angular Shared Services Interview Questions

1. What is a Shared Service?

Answer

A Shared Service is an Angular service used to share business logic, data, or application state across multiple components through Dependency Injection.


2. Why are Shared Services used?

Answer

They eliminate duplicate logic, simplify component communication, reduce coupling, and centralize shared application state.


3. Why should providedIn: 'root' be used?

Answer

It creates a singleton service shared throughout the application while supporting tree shaking.


4. Why is BehaviorSubject preferred for shared state?

Answer

BehaviorSubject stores the latest value and immediately emits it to new subscribers, making it ideal for application state.


5. What is the difference between Subject and BehaviorSubject?

Answer

A Subject emits only future values to subscribers, while a BehaviorSubject requires an initial value and always provides the latest value to new subscribers.


6. Can unrelated components communicate using a Shared Service?

Answer

Yes.

Unrelated components can communicate by publishing and subscribing through a shared service.


7. Can Shared Services perform HTTP calls?

Answer

Yes.

Shared services commonly use HttpClient to centralize API communication.


8. Should components modify BehaviorSubject directly?

Answer

No.

Components should interact through service methods while the service controls the underlying subject.


9. What are common Shared Service use cases?

Answer

  • User session
  • Shopping cart
  • Theme management
  • Notifications
  • Search filters
  • Language settings
  • Shared dashboard state

10. What are the best practices?

Answer

  • Use singleton services.
  • Prefer BehaviorSubject for shared state.
  • Expose Observables instead of Subjects.
  • Keep services focused.
  • Avoid duplicate provider registrations.
  • Use Dependency Injection consistently.
  • Write unit tests.

Interview Cheat Sheet

Topic Remember
Registration providedIn: 'root'
Instance Singleton
Reactive State BehaviorSubject
Communication Shared Service
API Calls HttpClient
Encapsulation asObservable()
Shared Data Yes
Local Data Component
Dependency Injection Required
Best Practice Thin components, rich services

Summary

Angular Shared Services provide a clean and scalable way to share data, business logic, and application state between components. Combined with Dependency Injection and RxJS BehaviorSubject, they enable reactive communication, centralized state management, and reusable business logic. Shared Services are a cornerstone of enterprise Angular architecture and help keep components simple, maintainable, and focused on presentation.


Key Takeaways

  • ✔ Shared Services enable communication across multiple components.
  • ✔ Use providedIn: 'root' for application-wide singleton services.
  • ✔ Prefer BehaviorSubject for reactive shared state.
  • ✔ Expose Observables instead of Subjects.
  • ✔ Centralize HTTP calls and business logic inside services.
  • ✔ Keep services focused and reusable.
  • ✔ Avoid storing component-specific state in shared services.
  • ✔ Use Dependency Injection instead of manual instantiation.
  • ✔ Shared Services improve scalability and maintainability.
  • ✔ Mastering Shared Services is essential for Angular interviews.

Next Article

➡️ 43-Component-Communication-Using-Services-QA.md