Change the page or the filter on a list that comes from an Angular resource, and the list goes empty until the new data arrives. NgRx v22 adds withPreviousValueOnLoading(), which keeps the old rows on screen in the meantime. It lives in @ngrx/signals/resource, is marked experimental, and shipped in NgRx 22.0.0 on 24 August.

Why the list goes empty

When a resource's params change, Angular sets its status to 'loading' and value() falls back to the default value, which is undefined unless you set defaultValue. A reload() with the same params is different: the status is 'reloading' and Angular already keeps the previous value. So the flash shows up when you page or filter, not when you refresh.

Using it

extendResource takes any resource, including httpResource and rxResource, applies the extensions and returns the same object with the same type:

import { signal } from '@angular/core';
import { httpResource } from '@angular/common/http';
import { extendResource, withPreviousValueOnLoading } from '@ngrx/signals/resource';

export class Orders {
  page = signal(1);

  orders = extendResource(
    httpResource<Order[]>(() => `/api/orders?page=${this.page()}`),
    withPreviousValueOnLoading(),
  );
}

While the next page loads, orders.value() returns the last rows, status() still says 'loading' and isLoading() stays true, so you can still dim the list or show a spinner. On the very first load there is nothing to keep, and value() is undefined. Errors are not hidden: in the 'error' state value() still throws, and NgRx has withPreviousValueOnError() and withValueOnError() for that case.

extendResource calls inject(), so create the resource in a field initializer or another injection context. To apply the extension to every extendResource call, register it once with provideResourceExtensions(withPreviousValueOnLoading()).

One open bug

In NgRx 22.0.1, the latest release, a computed that first reads value() while the resource is loading can stay stuck on the old value (issue #5224). During loading the cached value comes back without reading a signal, so the computed records no dependency. The workaround in the issue is to also read isLoading() inside the computed. A fix has been approved but is not released yet.

Being experimental, the API may change without the usual breaking-change notice. For paged and filtered lists I'd still use it, with that bug in mind for derived values.

Sources

I post short notes like this on LinkedIn.

Need help with this?

Two order lists on page 2: without the extension the list is empty while loading because value() is undefined; with withPreviousValueOnLoading() the old rows #1041 to #1044 stay visible. Below, extendResource wrapping an httpResource of orders with withPreviousValueOnLoading().

Have an Angular app that needs a senior hand?

Tell me about your app and what is slowing your team down. We go through it on a call and you leave with concrete next steps.