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
BehaviorSubjectfor 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
BehaviorSubjectfor 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
BehaviorSubjectfor 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