Signals + Async Data — Built-In
resource() & httpResource()
resource() is Angular's new async primitive — state, loading, and error all exposed as signals you can read in templates.
What you'll learn
- Build a resource backed by a signal request
- Read value, isLoading, and error as signals
- Use httpResource for HttpClient-backed data
resource() is Angular 20’s signal-native answer to “load data and show it”. It re-runs whenever the request signal changes, exposes loading and error as signals, and integrates cleanly with the template.
Basic resource
import { Component, resource, signal } from '@angular/core';
interface User { id: string; name: string }
@Component({
selector: 'app-users',
standalone: true,
template: `
<input [value]="query()" (input)="query.set($any($event.target).value)" />
@if (users.isLoading()) {
<p>Loading...</p>
} @else if (users.error()) {
<p>Error: {{ users.error() }}</p>
} @else {
@for (u of users.value(); track u.id) {
<li>{{ u.name }}</li>
}
}
`,
})
export class UsersComponent {
query = signal('');
users = resource({
request: () => ({ q: this.query() }),
loader: ({ request }) =>
fetch(`/api/users?q=${request.q}`).then(r => r.json() as Promise<User[]>),
});
} The request function reads signals — when any of them change, the loader re-runs. Previous in-flight loads are canceled.
What it exposes
users.value()— the latest data, orundefinedusers.isLoading()— boolean signalusers.error()— the last error, if anyusers.reload()— manually re-runusers.set(...)— overwrite the current value (e.g. optimistic update)
httpResource
httpResource is the same API but powered by HttpClient, so interceptors, typed responses, and cancellation all work as expected.
import { httpResource } from '@angular/common/http';
users = httpResource<User[]>(() => `/api/users?q=${this.query()}`); When to use it
resource() shines for component-level async data — list views, detail views, anything that depends on inputs. For large shared state, lift it into a service or reach for NgRx.