Angular Tips: Transforming Observables into Signals for Enhanced Reactivity
deji adesoga

deji adesoga @desoga

About: Software Developer and Content Creator.

Joined:
Apr 29, 2018

Angular Tips: Transforming Observables into Signals for Enhanced Reactivity

Publish Date: Feb 1 '24
20 12

Unlock Your Angular Signals Knowledge with my New Course: Demystifying Reactivity with Angular Signals

Introduction

There’s always been a love-hate relationship with front-end devs and Angular.

It’s a really powerful framework, and yet so hard to get into it,

especially if you’re a newer engineer.

Thankfully, Angular keeps evolving, year by year, and continuously offerring better, easier, and more efficient ways to manage data and reactivity.

One such evolution is the conversion of observables to signals using Angular's interoperability API.

This post explores this transformative process and its significance in enhancing application reactivity and performance.

Understanding Observables and Signals in Angular

In Angular, observables are a core part of managing data streams, particularly when fetching data from REST APIs. They provide a powerful way to handle asynchronous data flows. However, managing these observables, especially in complex applications, can become challenging. This is where signals come in, offering a simpler and more reactive way to handle data.

The toSignal API: The Hero We All Needed

The toSignal method, a part of Angular's interoperability API, is pivotal in converting observables to signals. It enhances data stream management, making applications more efficient and responsive. The toSignal API accepts various data types and a source, such as data from a REST API, and can also take an initial value, defaulting to 'undefined' if not provided.

A basic example of the toSignal API in use:



import { toSignal } from '@angular/interoperability';

let observable = fetchData('https://my-api.com/data');
let signal = toSignal(observable, []);


Enter fullscreen mode Exit fullscreen mode

In this instance, fetchData is a function that returns an observable from a REST API, which is then transformed into a signal.

Implementing Reactive Primitives for Efficient State Management

Angular's reactive primitives - effects, computed, and signal - play a crucial role in managing state reactively. The focus here is on the computed primitive, which wraps the environment and implements the first reactive primitive. An observable variable is created to hold API response data, which is then converted to a signal.



import { computed, observable, toSignal } from '@angular';

let environment = computed(() => { /* Computed environment code here */ });
let products$ = observable(fetchData('https://my-api.com/products'));
let productsSignal = toSignal(products$, []);

Enter fullscreen mode Exit fullscreen mode




Integrating Signals into Angular Components

To utilize the products signal in a component, Angular 17's new @For loop syntax provides a better alternative to the traditional ngFor. This integration significantly simplifies the component's code and enhances reactivity.



<template>
@for (product of productService.productSignal(); track product){
<!-- Component code here -->
} @empty {
<div>No Products Available</div>
}
</template>

Enter fullscreen mode Exit fullscreen mode




The Benefits of Converting Observables to Signals

The conversion offers several advantages:

  • Simplified State Management: Signals provide a more straightforward approach to managing data streams compared to observables.

  • Enhanced Reactivity: Signals update the UI reactively, ensuring that changes in data are immediately reflected.

  • Performance Improvements: By reducing the reliance on observables in templates, potential performance issues are minimized, leading to faster, more responsive applications.

Conclusion

Converting observables to signals in Angular represents a significant step towards more efficient and reactive web applications. By understanding and implementing this process, developers can optimize the performance and maintainability of their applications. As Angular continues to evolve, embracing these advancements is key to staying ahead in the dynamic world of web development.

Comments 12 total

  • Pierre Bouillon
    Pierre BouillonFeb 1, 2024

    Angular's new control flows cannot be used like you did, the correct syntax of a @for block is:

    @for(product of products; track product.id) {
      <!-- Component code here -->
    }
    
    Enter fullscreen mode Exit fullscreen mode

    Also, I'm not sure that using toSignal on observables might result in any performance improvements: as you said, it will eagerly subscribe to all observables, leading to more active subscriptions and pipeline being executed.

    • deji adesoga
      deji adesogaFeb 1, 2024

      Thank you for the correction on the syntax, I've made the correction. Cheers!!!

      As for the toSignal interop API, there's a potential performance improvement, since we now have access to the different Signal methods and API.

  • João Angelo
    João AngeloFeb 1, 2024

    Deji Adesoga
    Nice Tips
    Thanks for sharing

  • teej107
    teej107Feb 2, 2024

    Signals are the hot new Angular feature but I think having the mindset that Observables are too complex and Signals are the fix is a dangerous one. I don't think either is a replacement for the other.

    The blanket statement that is relying on Observables in templates reduce potential performance issues is misleading. I'm not sure what Signal specific optimizations Angular is performing under the hood but (to my understanding) a Signal and Observable will only be as performant as their source.

    It is also important to know that toSignal may potentially lead to memory leaks depending on if you are using it in a root service or elsewhere since it relies on the injector's context to unsubscribe from the source. This article does a much better job at explaining: Navigating the Nuances of toSignal in Angular: What to Know

    • deji adesoga
      deji adesogaFeb 3, 2024

      Yes Signals have not come replace Observables. However I disagree with the notion that Observables are not complex. They are complex and require a steep learning curve and take time to master, compare to how other frameworks, work.

  • Lars Rye Jeppesen
    Lars Rye JeppesenFeb 2, 2024

    I can't wait to ditch ZoneJS. It will unlock a lot of awesome improvements (top level await for example), and insane speeds with local change detection. Signals unlock so much good stuff.

    I tried removing it (now that Angular 17.1 has an experimental flag that makes it a noOp), but sadly we're relying on Angular/Fire - and that package throws up without ZoneJS.

    Great article, cheers

    • deji adesoga
      deji adesogaFeb 3, 2024

      Good to know you're receptive to the concept of Signals. Not many are receptive to it in the community.

      As for Angular fire, I hope they provide a Signal compatible update soon. Thank you for reading cheers!

      • Lars Rye Jeppesen
        Lars Rye JeppesenFeb 5, 2024

        I just went zoneless with one of our apps, as the opt-out of zonejs is now possible with Angular 17.1. Small hickups (3rd party stuff) but in general it works well.

        I found a workaround for Angular/Fire - just keep zonejs in angular as a polyfill, but opt out in the configuration. This will keep Angular/Fire and Angular/Components happy.

        All components have now migrated to input(), it is really beautiful and developer friend as well. Loving how this is going. When we get signal-based components, (hopefully in V18) , performance gains will be on fire, I'm tellin' ya :)

        • deji adesoga
          deji adesogaFeb 5, 2024

          I love your enthusiasm towards the adoption of the new updates. Believe me, not many want Signals to get integrated based on most of the interactions I've seen online so far.

          I haven't touched Firebase in a long time, but is there a way for you to share the work around. I believe this will be beneficial to many in the community. Perhaps if you could share your integration on Stackblitz.

          I'd like to create some content around it. Kindly let me know if you're open to it. Thanks.

          • Lars Rye Jeppesen
            Lars Rye JeppesenFeb 6, 2024

            Hi!
            It's very simple: do not remove zonejs from the package.json or angular.json of your project.
            Just disable zoneJS in the angular app.config file:


            import { ɵprovideZonelessChangeDetection as provideZonelessChangeDetection} from '@angular/core';

            ... in the configuration, add

            export const appConfig: ApplicationConfig = {
            providers: [
            ...other providers,
            provideZonelessChangeDetection()

            • deji adesoga
              deji adesogaFeb 6, 2024

              Awesome. I'll do well to try this out soon. Thank you.

Add comment