Category: Uncategorized

  • Angular Signals and Observables: A Clean Pattern for Managing State

    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:

    1. A data service that fetches and exposes data via observables.
    2. 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.