I recently did a presentation at work about Angular Signals. One section comparing RxJS and Signals noted that RxJS remained better at asynchronous work. Consider, for example, a text field that takes user input and maps it into API search results.
const searchResults$ = queryValue.pipe(
switchMap(query => this.apiService.search(query))
); During the presentation, I said the best way to create an asynchronous computed Signal was to use RxJS.
computed()will not accept anasynccallback. It also does not provide adone()function that can be called in a callback. You must synchronously return a value from yourcomputed()callback.After some experimentation, I figured out how to do it. You actually have to go back to RxJS and wrap it with
toSignal().
Then a member of the audience raised his hand and asked if I knew about the resource api. It was a new feature coming to Angular that had been announced just a day or two before my presentation.
You can read the pull request yourself. It creates a new function, resource(), which is essentially asyncComputed().
To return to our previous example, here’s how you would use Signals to map user input into a list of search results with resource():
export class SearchComponent {
protected query = model('');
protected searchResults: Signal<string[]>;
constructor(apiService: ApiService) {
this.searchResults = resource({
request: this.query,
loader: async () => {
const query = this.query();
const response = await apiService.search(query);
return response.json();
}
});
}
} This tells Angular, “if this.query ever changes, ping the API using this async method and return the results in this.searchResults, a Signal we can use anywhere in the class or template.”
resource() will arrive with Angular 19. There’s a bunch of other stuff you can do with it too. At the moment, the only downside I can see is that it can’t easily do some RxJS things, like debouncing.
But you know what? resource() is a promising start. I’m excited we got an official way to make async computed Signals.