Article
Stop Keeping Users in the Dark: Force Loading States with Angular 22
Angular 22 introduces a new capability for resources: the ability to throw a specific ResourceParamsStatus (IDLE or LOADING) inside a resource to force a given state.
Let's illustrate why this is useful with a common UI pattern: a debounced search field.
The Debounce Dilemma
When a user starts typing in a search field, the common behavior is to delay the API call until they've stopped typing for a short period of time (often 300 to 500 milliseconds). This avoids making an API call for every single keystroke, helping to limit API usage and prevent potential race conditions.
With Angular 22, you can debounce the value of a Signal using the new debounced utility. It takes two parameters: the source signal and the delay in milliseconds.
The debounced utility exposes a resource, and you can pass its value to an httpResource to call the API once the delay is over. As the API call takes time, you can use the httpResource's .isLoading() signal to display a visual indicator, such as a spinner.
// 1. Raw user input signalsearchInput = signal('');
// 2. Debounce the input by 300msdebouncedSearch = debounced(this.searchInput, 300);
// 3. API call based on debounced valueprotected readonly pizzeriasResource = httpResource<Page<PizzeriaSummary>>(() => ({ url: '/api/pizzerias', params: { page: 1, limit: this.limit, search: this.debouncedSearch.value(), },}));That's quite usual, and something we were used to doing with Reactive Forms in the past. But there's a catch.
Technical Reality vs. User Expectations
The issue is that the visual indicator's appearance is based on your own technical understanding of the app: it starts only when we actually make the API call.
For most users, they have no clue about this internal delay. They started typing and they expect to get results immediately.
If they type only 3 characters, they'll quickly see this visual indicator. But what about their first experience if they decide to type a long search term? It means they keep typing, but nothing happens on screen.
Forcing the Loading Status
By being able to throw ResourceParamsStatus, we can force the loading state as soon as they start typing.
As the debounced search is a Resource, it exposes an isLoading() signal. Inside the httpResource, we can use it to explicitly force the status:
protected readonly pizzeriasResource = httpResource<Page<PizzeriaSummary>>(() => { if (this.debouncedSearch.isLoading()) { throw ResourceParamsStatus.LOADING; }
return { url: '/api/pizzerias', params: { page: 1, limit: this.limit, search: this.debouncedSearch.value(), }, };});By throwing ResourceParamsStatus.LOADING when this.debouncedSearch.isLoading() is true, the httpResource immediately switches to a loading state. The user sees the visual indicator as soon as they start typing, bridging the gap between technical implementation and user expectation for a much smoother experience.
Keep Up with New Angular Features
Wondering when features like debounced and ResourceParamsStatus were released, or checking if your current Angular version supports them?
Discover Angular Can I Use to instantly find the availability of every Angular API, utility, and component. It's the easiest way to know exactly what features you can use right now!