The Vision Behind It: Loading Async Data With Signals

The concept for these APIs stems from a pull request submitted by Alex Rickabaugh. At its heart, the idea is to use Signals as the mechanism for handling asynchronous resource loading. The resource API works with Promises, while rxResource is built around Observables, giving developers the option to pick whichever paradigm they're more comfortable with. Both return a WritableResource instance, which makes it possible to modify the resource's data directly on the client side.

A resource exposes a set of signals that reflect its current state:

  • Value: Holds the actual data returned by the resource, representing the outcome of the query.
  • Status: Indicates the current phase of the resource. The possible statuses are listed below:

ResourceStatus in Angular 19

  • Error: Supplies information about any issues that came up while retrieving data.

Setting Up a Resource

Creating a resource is straightforward:

Creating a resource Angular 19

This leads to the output shown below. Observe that the status starts out as "Loading" (2) and eventually transitions to "Resolved" (4).

Resource simple output

Modifying Resource Data on the Client

If you need to change the resource's data without making another server call, the update() method on the value signal is what you want. The template and component below demonstrate the pattern:

Update resource data locally

The updateResource() method swaps the current resource value for a different string locally.

Update Resource Data locally

Here's what you'll see after that runs. Pay attention to the status reading "Local" (5), signaling a client-side update.

Update resource data locally output

Triggering a Resource Refresh

Let's add a Refresh button to the template so the user can manually re-fetch the data.

Refreshing a resource

The reload function in the example below tells the resource loader to run once more. If the user clicks Refresh multiple times in a row, the loader won't fire again until the ongoing request completes. This behavior mirrors how exhaustMap works in Rxjs.

Refresh Resource in Angular 19

In the output that follows, you can observe the status shifting from "Reloading" (3) to "Resolved" (4).

Refresh Resource Output in Angular 19

Signal-Driven Data: Loading Resources Dynamically

Imagine you want to pull posts based on an postId signal. You can pass that signal straight into the endpoint as a request parameter:

Load data with signals template

Using postId as a request parameter lets you retrieve data dynamically, driven by whatever value that signal currently holds. A quick demo:

Load data with signals component

The output looks like this:

Load data with Signals output

That setup works fine for the first fetch, but it's not reactive. Loaders in Angular's resource API run untracked by default. So if postId changes after the resource is first created, the loader won't kick in again on its own.

To make things truly reactive, you have to explicitly link the signal to the resource's request parameter. That connection forms a dependency between the resource and the signal, so any change to the signal's value automatically re-triggers the loader.

Let's wire up a button that sets postId to a random number.

Signal change template

Inside the component, we add a method that assigns a random number to the postId signal. We also bind postId to the request parameter of the resource to keep the reactivity intact.

Signal Change Component

Dealing with Local Updates While Requests Are In Flight

If you make a local change while the resource is still waiting on a remote call, you can run into a race condition. The abortSignal() function helps us handle that gracefully.

By handing an AbortSignal to the resource's loader, we can stop a request that's already underway if that signal gets aborted. This becomes especially handy when a new request fires off before the previous one has wrapped up.

Here's how the flow works:

  • Local change applied: The user tweaks the data locally, which sets off a new request.
  • Abort signal created: An AbortSignal is generated and passed along to the resource's loader.
  • Pending request canceled: If an earlier request is still active, it gets canceled using the AbortSignal.
  • Fresh request launched: The loader fires again with the updated postId and the new AbortSignal.
  • Data retrieved and applied: The new request completes, and the resource's value gets overwritten with the latest data.

The example below fetches data based on the newest value of the signal and cancels any request that's still running if multiple triggers occur.

Abort Signal Component

Watching Multiple Signals for Reactive Loading

A resource can stay in sync with changes across multiple signals, enabling richer data-fetching scenarios. Bind several signals to the request parameter, and the loader will re-run whenever any of those signals shifts.

In the example below, both postId and userId get assigned random numbers, and the resource is set up to react when either one changes:

Multiple Dependenies in resources Angular 19

When either userId or postId changes, the loader is invoked again. This guarantees that the resource always mirrors the latest state of its dependent signals.

Building Reusable Resource Functions

For cleaner, more maintainable code, you can define resource functions that are reusable across your app. These functions wrap the logic needed to create resources with particular settings, making them easy to share.

Here's one such reusable function:

Reusable resources in Angular 19

In that snippet, myResource can be reused across various parts of the application, promoting cleaner code and better reusability.

RxResource: Harnessing Observables for Asynchronous Data Handling

For applications that already embrace Observables, the rxResource API offers a robust solution for managing asynchronous data workflows. It mirrors the resource API's functionality but emits data through an Observable stream.

What Sets rxResource Apart from resource

  • Observable-Driven: Instead of raw values, rxResource relies on Observables to deliver a continuous data stream, enabling richer reactive patterns.
  • No abortSignal Required: Because subscriptions to Observables can be cleanly terminated, the explicit abortSignal is unnecessary.
  • Single-Emission Focus: In its current form, rxResource processes only the first value emitted by the Observable; any subsequent values are disregarded.
  • Mutable Local State: Similar to resource, rxResource supports modifying local resource state via Observables.

The snippet below demonstrates how to build a resource with rxResource:

rxResource - Observables based resource API in Angular 19

Here, the loader function produces the posts as an Observable. Subscribing to this stream allows you to respond to changes and trigger side effects as needed.

Final Thoughts

The introduction of resource and rxResource APIs in Angular marks a notable advancement in handling asynchronous operations. They bring a more declarative and streamlined method to data fetching, which contributes to better developer experience and application responsiveness.

Even though these APIs are in developer preview, they have the potential to transform data management strategies in Angular. By capitalizing on Signals and Observables, they deliver a versatile and performant pathway for managing reactivity and data flow.

Github PR: https://github.com/angular/angular/pull/58255
Code repository: https://github.com/Ingila185/angular-resource-demo
Stackblitz Playground: https://stackblitz.com/edit/stackblitz-starters-hamcfa?file=src%2Fmain.ts

Special thanks to Enea Jahollari for the comprehensive write-up on resource and rxResource for Push Based.