
Async data in Angular has always been a bit of a challenge—especially when juggling loading states, error handling, and subscriptions. But with Angular 19, rxResource
changes the game completely.
Let’s break down how we used to handle async data, what the problems were, and how rxResource
solves them beautifully.
🧠 The Old-School Way: subscribe()
(Avoid This!)
@Component({...})
export class UserListComponent {
private http = inject(HttpClient);
users: { name: string }[] = [];
constructor() {
this.http.get<{ name: string }[]>('https://jsonplaceholder.typicode.com/users')
.subscribe(data => this.users = data);
}
}
🚫 What’s Wrong Here?
- Manual subscription = potential memory leaks
- No native handling for loading or errors
- Clunky, imperative approach
✅ Better: Async Pipe (Cleaner, But Limited)
@Component({...})
export class UserListComponent {
private http = inject(HttpClient);
users$ = this.http.get<{ name: string }[]>('https://jsonplaceholder.typicode.com/users');
}
<ul *ngIf="users$ | async as users; else loading">
<li *ngFor="let user of users">{{ user.name }}</li>
</ul>
<ng-template #loading>Loading...</ng-template>
Pros:
✔️ Auto-unsubscribes
✔️ Cleaner than subscribe()
But Still:
❌ No built-in state tracking
❌ Error handling is manual
❌ Not ideal for reactive workflows with Signals
🚀 Enter rxResource
— Angular 19’s Game Changer
Angular 19 introduces rxResource
, a smarter, Signal-friendly way to manage async data. It wraps loading, error, and data state into one reactive resource.
@Component({...})
export class UserListComponent {
private http = inject(HttpClient);
users = rxResource(() => this.http.get<{ name: string }[]>('https://jsonplaceholder.typicode.com/users'));
}
<ng-container *ngIf="users.loading(); else content">Loading...</ng-container>
<ng-template #content>
<ng-container *ngIf="users.error(); else userList">
Error: {{ users.error()?.message }}
</ng-container>
</ng-template>
<ng-template #userList>
<ul><li *ngFor="let user of users.data()">{{ user.name }}</li></ul>
</ng-template>
🔥 Why This Rocks:
- Built-in support for loading, error, and data
- Fully reactive with Signals
- Minimal boilerplate
- No need to
unsubscribe
— ever
📦 Bonus: rxResource
with Parameters + Refresh
@Component({...})
export class UserDetailComponent {
private http = inject(HttpClient);
userId = signal(1);
user = rxResource(() =>
this.http.get<{ name: string }>(`https://jsonplaceholder.typicode.com/users/${this.userId()}`)
);
fetchUser(id: number) {
this.userId.set(id);
this.user.refresh(); // Manually trigger refetch
}
}
<button (click)="fetchUser(1)">User 1</button>
<button (click)="fetchUser(2)">User 2</button>
<div *ngIf="user.loading(); else content">Loading...</div>
<ng-template #content>
<div *ngIf="user.error(); else userInfo">
Error: {{ user.error()?.message }}
</div>
</ng-template>
<ng-template #userInfo>
<p>{{ user.data()?.name }}</p>
</ng-template>
This is next-level reactive programming: easy parameter switching, clean reactivity, and precise control.
🎯 Summary: Why rxResource
Is a No-Brainer
Feature | subscribe() | async pipe | rxResource ✅ |
---|---|---|---|
Auto-unsubscribe | ❌ | ✅ | ✅ |
Loading state | ❌ | ❌ | ✅ |
Error handling | ❌ | ❌ | ✅ |
Signal integration | ❌ | ❌ | ✅ |
Code readability | ❌ | ⚠️ | ✅ |
🧠 Final Thoughts
If you’re still manually subscribing or relying solely on async
, now’s the time to explore rxResource
. It’s reactive, elegant, and built for the modern Angular ecosystem.
Angular 19 is all about signals — and rxResource
is how you keep your data reactive, safe, and maintainable