Angular Theme Service Implementation
This challenge asks you to build a reusable Angular service that manages and applies application themes. A theme service allows you to easily switch between different visual styles (e.g., light, dark, high-contrast) without modifying component templates directly, promoting maintainability and a consistent user experience. This is a common requirement in modern web applications.
Problem Description
You need to create an ThemeService in Angular that allows components to:
- Set a theme: The service should accept a theme name (string) as input and store it.
- Get the current theme: The service should provide a method to retrieve the currently active theme name.
- Subscribe to theme changes: Components should be able to subscribe to an observable that emits the current theme whenever it changes.
- Apply theme styles: The service should dynamically apply CSS variables based on the selected theme. You will be provided with a set of CSS variables for each theme.
Key Requirements:
- The service should be injectable into Angular components.
- The theme changes should be observable and reactive.
- The service should handle invalid theme names gracefully (e.g., by defaulting to a standard theme).
- The service should not directly manipulate the DOM. Instead, it should set CSS variables that components can then use.
Expected Behavior:
- When a component calls
setTheme('dark'), the service should store 'dark' as the current theme and emit an event. - When another component calls
getTheme(), it should return 'dark'. - Any component subscribed to the theme changes observable should receive an update when the theme changes.
- If an invalid theme name is provided (e.g., 'purple'), the service should log an error and default to a predefined theme (e.g., 'light').
Edge Cases to Consider:
- What happens if the service is called multiple times with the same theme?
- What happens if the service is called with a theme that is not defined?
- How should the service handle initialization (e.g., loading a theme from local storage)? (This is not required for the core functionality, but a good consideration for a production-ready service).
Examples
Example 1:
Input: setTheme('dark') followed by setTheme('light')
Output: The application's CSS variables are updated to reflect the 'dark' theme, then the 'light' theme.
Explanation: The service stores the theme and emits an event, triggering components to update their styles based on the new CSS variables.
Example 2:
Input: setTheme('invalidTheme')
Output: The service logs an error message and sets the theme to 'light' (the default).
Explanation: The service handles the invalid theme gracefully by defaulting to a known theme.
Example 3:
Input: A component subscribes to the theme changes observable and calls setTheme('dark').
Output: The component receives an emitted value of 'dark' from the observable.
Explanation: The observable pattern ensures that components are notified of theme changes in real-time.
Constraints
-
Theme Definitions: You will be provided with the following theme definitions as constants within the service:
const themes = { light: { '--background-color': '#ffffff', '--text-color': '#000000', '--primary-color': '#007bff', }, dark: { '--background-color': '#222222', '--text-color': '#ffffff', '--primary-color': '#00aaff', }, }; -
CSS Variable Application: The service should apply the theme by setting CSS variables on the
document.documentElement(the<html>element). -
Performance: The service should be efficient and avoid unnecessary DOM manipulations. Setting CSS variables is generally performant.
-
Error Handling: Invalid theme names should be logged to the console.
Notes
- Consider using RxJS observables for reactive theme changes.
- Think about how to make the service extensible to support more themes in the future.
- You don't need to create a full Angular application for this challenge. Focus solely on the
ThemeServiceimplementation. - The goal is to create a clean, reusable, and well-documented service.
- Assume that the CSS variables defined in the
themesobject are already used in your application's CSS.