Introduction
In modern Angular applications, handling reactive data streams efficiently is crucial. This pattern ensures:
- Separation of concerns – Data fetching and UI reactivity are managed separately.
- Optimised reactivity – Using signals to prevent unnecessary UI updates.
- Scalability – A structured approach that can be extended with facades if needed.
This post presents a pattern using two services:
- A data service that fetches and exposes data via observables.
- A signal-based service that converts the observable into a signal for UI components.
Note: When I wrote this post, I was working on a team that did not want observables in components. To handle this, you could introduce a facade service that wraps everything in signals—including the startFeed observable—and expose it via a view model. The component would then trigger the data flow by calling a signal function in the template.
1. Data Service: Handling the Data Fetching
This service is responsible for fetching data and exposing an observable.
Key Points:
- startFeed() fetches data and updates the BehaviorSubject.
- listen() exposes the current state as an observable for external consumers.
2. Signal Service: Converting the Observable into a Signal
This service wraps the observable into a signal and provides derived signals for specific properties.

Key Points:
- toSignal() creates a reactive signal from the observable.
- Computed signals ensure only necessary properties are exposed.
- startFeed() is exposed so it can be subscribed to in the template using async.
3. Using the Signal Service in a Component
The component subscribes to “ using the async pipe, ensuring it follows reactive best practices.

Key Points:
- start() assigns feed$ to startFeed() and binds it in the template using async.
- dataTitle is a signal, meaning it updates automatically when new data arrives.
Alternative Approach: Using a Facade Service
If you don’t want observables in the component, you could introduce a facade service that exposes everything as signals—including the startFeed() observable wrapped inside a signal.
Then, in the component:

This approach keeps all observable logic out of the component while maintaining a clean reactive API.
Conclusion
This pattern provides:
✅ Separation of concerns – Data fetching, state management, and UI logic are cleanly divided.
✅ Optimised rendering – UI only updates when necessary.
✅ Flexibility – Works with or without observables in the component.