Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions adev/src/content/guide/signals/resource.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,54 @@ The `id` value must be unique within your application and identical on the serve

IMPORTANT: Because the cached value is serialized into the page's HTML, avoid setting `id` on resources that load data specific to the user who triggered the server-side render, especially if the rendered HTML can be cached or shared between users.

## Chaining resources

Sometimes one resource depends on the result of another. You can express this dependency using the `chain` function available in the `params` context object.

```typescript
import {resource} from '@angular/core';

const userResource = resource({
params: () => ({id: getUserId()}),
loader: ({params}) => fetchUser(params),
});

const userPostsResource = resource({
params: ({chain}) => chain(userResource)?.id,
loader: ({params: userId}) => fetchPostsForUser(userId),
});
Comment thread
JeanMeche marked this conversation as resolved.
```

`chain(userResource)` reads the value of `userResource` and automatically propagates its status to `userPostsResource`:

- If `userResource` is **loading**, `userPostsResource` also enters the `loading` state and its loader does not run.
- If `userResource` is **idle**, `userPostsResource` also becomes `idle`.
- If `userResource` is in an **error** state, `userPostsResource` also enters the `error` state.
- If `userResource` is **resolved**, `chain` returns its value, which `userPostsResource` then uses as its params.

When `userResource` is not yet resolved, `chain` throws to propagate its status, so the params function does not continue. When `userResource` is resolved, `chain` returns its value, which can itself be `undefined` if that's the resolved value. The example handles this with `chain(userResource)?.id`, so an `undefined` value results in `undefined` params and `userPostsResource` becomes `idle`.

NOTE: Pass the chained value directly as the params value rather than wrapping it in an object. A params value like `{userId: undefined}` is still a defined value, so the loader would run with an `undefined` id instead of the resource becoming `idle`.

### Chaining vs. reading resource values directly

You might be tempted to read a resource's value directly inside `params`:

```typescript
// Avoid: reads value() directly without status propagation
const userPostsResource = resource({
params: () => {
const user = userResource.value(); // may be undefined
return user ? {userId: user.id} : undefined;
},
loader: ({params}) => fetchPostsForUser(params.userId),
});
```

While this works, returning `undefined` from `params` makes the resource go `idle` rather than reflecting the actual state of the upstream resource. Using `chain` is preferred because it correctly mirrors `loading` and `error` states.

Reach for `chain` only when the downstream resource performs its own async work that depends on the upstream value. If you only need to derive a value synchronously from a resource, use `computed` instead.

## Reactive data fetching with `httpResource`

[`httpResource`](/guide/http/http-resource) is a wrapper around `HttpClient` that gives you the request status and response as signals. It makes HTTP requests through the Angular HTTP stack, including interceptors.
Expand Down
Loading