Angular Signals with RxJS - A practical example

This article will delve into the seamless fusion of Angular Signals and RxJS, highlighting how these two technologies can effortlessly blend together, showcasing that RxJS continues to shine brightly in their combined usage. The combination of these two technologies can lead to a more efficient and streamlined development process, allowing developers to create more complex applications with ease. By leveraging the power of Angular Signals and RxJS, developers can create reactive applications that are both scalable and maintainable.

Initial Setup

 <input type="text" (keyup)="search($event)" />

just an input with a keyup event.

 export class AppComponent {
  http = inject(HttpClient);

  search(event: Event) {
    const value = (event.target as HTMLInputElement).value;
  }
}

Inside our class has been injected HttpClient and created a search function which gets a value of the input but doesn't do anything else.

Implementing API call

Now, the challenge lies in implementing the retrieval of data from the API both upon initialization and after entering text into the input. We aim to incorporate debouncing to prevent excessive API calls, ensuring that we don't overlook any submitted values already present.

This is exactly the case where RxJS shines in comparison to signals. What we are getting from signals is simply a state to read or update the value and computed which returns some value based on another signal. The last thing that we get from signals is effect which allows us to do something when our signal is changed.

This is not what we need for our case here. We have the case where RxJS can help us a lot.

export class AppComponent {
  ...
  searchSig = signal<string>('');

  search(event: Event) {
    const value = (event.target as HTMLInputElement).value;
    this.searchSig.set(value);
  }
}

Our first step here is to create a signal which stores our search value. Now we can update this signal when we change the input with set function.

But it is not all. We want to make an API call every single time when we change our search. The main problem is that we can't write this code with signal effectively. Now we have a function in Angular which allows us to transform signal to the observable.

import { toObservable, toSignal } from '@angular/core/rxjs-interop';

export class AppComponent {
  ...
  searchSig = signal<string>('');
  articles$ = toObservable(this.searchSig).pipe(
    debounceTime(300),
    distinctUntilChanged(),
    switchMap((searchTerm) =>
      this.http.get<Article[]>(
        `http://localhost:8080/articles?title=${searchTerm}`
      )
    )
  );
}

In this instance, we employed the toObservable function to convert our signal into an observable, enabling the application of RxJS functions. We incorporated debounceTime to prevent excessive API calls, distinctUntilChanged to avoid redundant API calls with identical data, and switchMap to execute an HTTP request

So this code just creates an observable from the signal.

This doesn't signal a return to our previous less efficient practices, such as relying on async pipes or subscriptions. We're determined to steer clear of reverting to the digest cycle and the inherent issues it brings.

export class AppComponent {
  ...
  articlesSig = toSignal(this.articles$);
}

This is why here we created one more property which is a signal. We used toSignal function to convert our RxJS observable to a signal. Now we can safely use it inside our markup is a normal signal.

<div *ngFor="let article of articlesSig()">
  {{ article.title }}
</div>

or with the new built-in for loop.

@for (article of articlesSig(); track article.title) {
  {{ article.title }}
} 

We can see that our API call is done and we rendered a list of article. When we type something it refetches the data with the rules that we wrote in RxJS.

Conclusion

this article has explored the harmonious integration of Angular Signals and RxJS, demonstrating their synergistic collaboration. By showcasing the effective fusion of these two technologies, we've underscored the ongoing strength of RxJS within this combined usage.

Happy coding!