Angular 22 ·
Search-as-you-type in Angular 22 with debounced() and httpResource
Angular 22's experimental debounced() turns a signal into a resource that settles after a pause. How to feed it into httpResource for search-as-you-type.
Angular 22 has debounced() for the classic search box that should wait until the user stops typing. Until now that meant RxJS: debounceTime, switchMap and a subscription. debounced() takes a signal and a delay and returns a resource whose value settles once the input has been quiet that long. It comes from @angular/core and has been experimental since 22.0.
Search-as-you-type with httpResource
The official guide pairs it with resource(). With httpResource I'd write it like this, returning undefined for an empty query so that no request goes out:
query = signal('');
search = debounced(this.query, 300);
results = httpResource<Item[]>(() => {
const q = this.search.value();
return q ? `/api/search?q=${encodeURIComponent(q)}` : undefined;
});<input #box (input)="query.set(box.value)" />
@for (item of results.value() ?? []; track item.id) {
<li>{{ item.name }}</li>
}Every keystroke updates query. While the timer runs, search.status() is 'loading' and search.value() still returns the last settled text, so the URL only changes once typing stops. If the query changes again before the wait is over, the timer starts again from zero.
Details worth knowing
The first value isn't delayed: the resource starts out 'resolved' with the signal's current value. That's why the empty-query check matters. Without it, the page sends ?q= as soon as it loads.
debounced() needs an injection context, such as a field initializer, or an injector in its options. The only other option is equal, which defaults to Object.is. Instead of a number, the wait can also be a function that returns a promise, for example to wait longer while the query is still short. When the injector is destroyed, a pending timer is cancelled.
If you're on 22.0 or 22.1, update to at least 22.1.5, which fixed debounce timers that were never cleared. And it's experimental, which under Angular's release policy means it can change in any release, even a patch. For a search box that's a risk I'd take.
Sources
- Debouncing signals with debounced (angular.dev guide)
- debounced API reference
- Async reactivity with resources (angular.dev guide)
- debounce.ts at Angular v22.2.3
I post short notes like this on LinkedIn.
Need help with this?
