Découvrez linkedSignal et la resource API d'Angular 19 : gérez les dépendances entre signaux et les appels HTTP asynchrones de façon réactive.
linkedSignal() : signaux dérivés modifiables
Angular 19 introduit linkedSignal(), un nouveau type de signal qui combine les propriétés de signal() (modifiable) et de computed() (dérivé d'une source). Il permet de créer un signal dont la valeur est initialisée automatiquement depuis une source, mais qui peut aussi être modifié manuellement.
Cas d'usage typique : une liste déroulante dont la sélection par défaut suit un signal parent, mais peut être changée par l'utilisateur.
import { Component, signal, linkedSignal } from '@angular/core';
@Component({
selector: 'app-product-select',
standalone: true,
template: `
<select (change)="selectedId.set(+$event.target.value)">
@for (p of products(); track p.id) {
<option [value]="p.id" [selected]="p.id === selectedId()">
{{ p.name }}
</option>
}
</select>
<p>Sélectionné : {{ selectedId() }}</p>
`
})
export class ProductSelectComponent {
products = signal([
{ id: 1, name: 'Angular' },
{ id: 2, name: 'React' },
{ id: 3, name: 'Vue' }
]);
// Initialisé depuis products(), mais modifiable manuellement
selectedId = linkedSignal(() => this.products()[0].id);
}
products()) change, selectedId se réinitialise automatiquement à la première valeur. Mais l'utilisateur peut aussi le modifier via selectedId.set().
Options avancées de linkedSignal
La forme longue de linkedSignal permet de contrôler comment la valeur est réinitialisée depuis la source, en tenant compte de l'ancienne valeur :
selectedId = linkedSignal({
source: this.products,
computation: (products, previous) => {
// Conserver la sélection si le produit existe toujours
const exists = products.some(p => p.id === previous?.value);
return exists ? previous!.value : products[0].id;
}
});
La resource API
La resource() API est une abstraction pour gérer les données asynchrones dans un composant. Elle prend un signal en entrée (la "request") et une fonction asynchrone (le "loader"), et retourne un objet avec l'état complet de la requête.
import { Component, signal, resource } from '@angular/core';
@Component({
selector: 'app-user-detail',
standalone: true,
template: `
@if (userResource.isLoading()) {
<p>Chargement...</p>
} @else if (userResource.error()) {
<p>Erreur : {{ userResource.error() }}</p>
} @else {
<h2>{{ userResource.value()?.name }}</h2>
}
`
})
export class UserDetailComponent {
userId = signal(1);
userResource = resource({
request: () => ({ id: this.userId() }),
loader: async ({ request }) => {
const response = await fetch(`/api/users/${request.id}`);
return response.json();
}
});
}
Quand userId change, la resource recharge automatiquement les données.
États d'une resource
Une resource expose plusieurs signaux pour suivre son état :
const r = resource({ ... });
r.value() // la donnée (ou undefined)
r.status() // 'idle' | 'loading' | 'refreshing' | 'resolved' | 'error' | 'local'
r.isLoading() // raccourci: status === 'loading' || status === 'refreshing'
r.error() // l'erreur si status === 'error'
// Actions
r.reload(); // force un rechargement
r.set(value); // modifie la valeur localement (status → 'local')
httpResource pour les appels HTTP
Angular 19 fournit également httpResource(), une version de resource() pré-configurée pour HttpClient :
import { Component, signal } from '@angular/core';
import { httpResource } from '@angular/common/http';
@Component({ ... })
export class PostsComponent {
page = signal(1);
posts = httpResource(() =>
`/api/posts?page=${this.page()}`
);
}
La requête HTTP est automatiquement annulée et relancée quand page() change.
Comparaison avec RxJS
// ===== Avant : avec RxJS =====
userId$ = new BehaviorSubject(1);
user$ = this.userId$.pipe(
switchMap(id => this.http.get(`/api/users/${id}`)),
shareReplay(1)
);
// ===== Après : avec resource() =====
userId = signal(1);
userResource = httpResource(() => `/api/users/${this.userId()}`);
resource() ne remplace pas RxJS pour tous les cas, mais simplifie drastiquement les patterns "fetch when signal changes" qui représentent la majorité des cas d'usage dans les composants.