@spoosh/angular 0.9.1 → 0.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +64 -51
- package/dist/index.d.mts +325 -104
- package/dist/index.d.ts +325 -104
- package/dist/index.js +109 -47
- package/dist/index.mjs +112 -47
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @spoosh/angular
|
|
2
2
|
|
|
3
|
-
Angular signals integration for Spoosh - `injectRead`, `injectWrite`, and `
|
|
3
|
+
Angular signals integration for Spoosh - `injectRead`, `injectWrite`, and `injectPages`.
|
|
4
4
|
|
|
5
5
|
**[Documentation](https://spoosh.dev/docs/angular)** · **Requirements:** TypeScript >= 5.0, Angular >= 16.0
|
|
6
6
|
|
|
@@ -23,7 +23,7 @@ const spoosh = new Spoosh<ApiSchema, Error>("/api").use([
|
|
|
23
23
|
cachePlugin({ staleTime: 5000 }),
|
|
24
24
|
]);
|
|
25
25
|
|
|
26
|
-
export const { injectRead, injectWrite,
|
|
26
|
+
export const { injectRead, injectWrite, injectPages } = create(spoosh);
|
|
27
27
|
```
|
|
28
28
|
|
|
29
29
|
### injectRead
|
|
@@ -115,7 +115,7 @@ async updateUserName(userId: number, name: string) {
|
|
|
115
115
|
}
|
|
116
116
|
```
|
|
117
117
|
|
|
118
|
-
###
|
|
118
|
+
### injectPages
|
|
119
119
|
|
|
120
120
|
Bidirectional paginated data fetching with infinite scroll support.
|
|
121
121
|
|
|
@@ -140,29 +140,26 @@ Bidirectional paginated data fetching with infinite scroll support.
|
|
|
140
140
|
`,
|
|
141
141
|
})
|
|
142
142
|
export class PostListComponent {
|
|
143
|
-
posts =
|
|
144
|
-
|
|
145
|
-
{
|
|
146
|
-
// Required: Check if next page exists
|
|
147
|
-
canFetchNext: ({ response }) => response?.meta.hasMore ?? false,
|
|
143
|
+
posts = injectPages((api) => api("posts").GET({ query: { page: 1 } }), {
|
|
144
|
+
// Required: Check if next page exists
|
|
145
|
+
canFetchNext: ({ lastPage }) => lastPage?.data?.meta.hasMore ?? false,
|
|
148
146
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
147
|
+
// Required: Build request for next page
|
|
148
|
+
nextPageRequest: ({ lastPage }) => ({
|
|
149
|
+
query: { page: (lastPage?.data?.meta.page ?? 0) + 1 },
|
|
150
|
+
}),
|
|
153
151
|
|
|
154
|
-
|
|
155
|
-
|
|
152
|
+
// Required: Merge all pages into items
|
|
153
|
+
merger: (pages) => pages.flatMap((p) => p.data?.items ?? []),
|
|
156
154
|
|
|
157
|
-
|
|
158
|
-
|
|
155
|
+
// Optional: Check if previous page exists
|
|
156
|
+
canFetchPrev: ({ firstPage }) => (firstPage?.data?.meta.page ?? 1) > 1,
|
|
159
157
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
);
|
|
158
|
+
// Optional: Build request for previous page
|
|
159
|
+
prevPageRequest: ({ firstPage }) => ({
|
|
160
|
+
query: { page: (firstPage?.data?.meta.page ?? 2) - 1 },
|
|
161
|
+
}),
|
|
162
|
+
});
|
|
166
163
|
}
|
|
167
164
|
```
|
|
168
165
|
|
|
@@ -203,42 +200,58 @@ export class PostListComponent {
|
|
|
203
200
|
| `input` | `TriggerOptions \| undefined` | Last trigger input |
|
|
204
201
|
| `abort` | `() => void` | Abort current request |
|
|
205
202
|
|
|
206
|
-
###
|
|
203
|
+
### injectPages(readFn, options)
|
|
207
204
|
|
|
208
|
-
| Option | Type | Required | Description
|
|
209
|
-
| ----------------- | --------------------------------------------- | -------- |
|
|
210
|
-
| `
|
|
211
|
-
| `
|
|
212
|
-
| `
|
|
213
|
-
| `canFetchPrev` | `(ctx) => boolean` | No | Check if previous page exists
|
|
214
|
-
| `prevPageRequest` | `(ctx) => Partial<TRequest>` | No | Build request for previous page
|
|
215
|
-
| `enabled` | `boolean \| Signal<boolean> \| () => boolean` | No | Whether to fetch automatically
|
|
205
|
+
| Option | Type | Required | Description |
|
|
206
|
+
| ----------------- | --------------------------------------------- | -------- | ------------------------------------------------- |
|
|
207
|
+
| `merger` | `(pages) => TItem[]` | Yes | Merge all pages into items |
|
|
208
|
+
| `canFetchNext` | `(ctx) => boolean` | No | Check if next page exists. Default: `() => false` |
|
|
209
|
+
| `nextPageRequest` | `(ctx) => Partial<TRequest>` | No | Build request for next page |
|
|
210
|
+
| `canFetchPrev` | `(ctx) => boolean` | No | Check if previous page exists |
|
|
211
|
+
| `prevPageRequest` | `(ctx) => Partial<TRequest>` | No | Build request for previous page |
|
|
212
|
+
| `enabled` | `boolean \| Signal<boolean> \| () => boolean` | No | Whether to fetch automatically |
|
|
216
213
|
|
|
217
214
|
**Context object passed to callbacks:**
|
|
218
215
|
|
|
219
216
|
```typescript
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
217
|
+
// For canFetchNext and nextPageRequest
|
|
218
|
+
type NextContext<TData, TRequest> = {
|
|
219
|
+
lastPage: InfinitePage<TData> | undefined;
|
|
220
|
+
pages: InfinitePage<TData>[];
|
|
221
|
+
request: TRequest;
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
// For canFetchPrev and prevPageRequest
|
|
225
|
+
type PrevContext<TData, TRequest> = {
|
|
226
|
+
firstPage: InfinitePage<TData> | undefined;
|
|
227
|
+
pages: InfinitePage<TData>[];
|
|
228
|
+
request: TRequest;
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
// Each page in the pages array
|
|
232
|
+
type InfinitePage<TData> = {
|
|
233
|
+
status: "pending" | "loading" | "success" | "error" | "stale";
|
|
234
|
+
data?: TData;
|
|
235
|
+
error?: TError;
|
|
236
|
+
meta?: TMeta;
|
|
237
|
+
input?: { query?; params?; body? };
|
|
224
238
|
};
|
|
225
239
|
```
|
|
226
240
|
|
|
227
241
|
**Returns:**
|
|
228
242
|
|
|
229
|
-
| Property | Type
|
|
230
|
-
| -------------- |
|
|
231
|
-
| `data` | `Signal<TItem[] \| undefined>`
|
|
232
|
-
| `
|
|
233
|
-
| `loading` | `Signal<boolean>`
|
|
234
|
-
| `fetching` | `Signal<boolean>`
|
|
235
|
-
| `fetchingNext` | `Signal<boolean>`
|
|
236
|
-
| `fetchingPrev` | `Signal<boolean>`
|
|
237
|
-
| `canFetchNext` | `Signal<boolean>`
|
|
238
|
-
| `canFetchPrev` | `Signal<boolean>`
|
|
239
|
-
| `
|
|
240
|
-
| `
|
|
241
|
-
| `
|
|
242
|
-
| `
|
|
243
|
-
| `
|
|
244
|
-
| `error` | `Signal<TError \| undefined>` | Error if request failed |
|
|
243
|
+
| Property | Type | Description |
|
|
244
|
+
| -------------- | ------------------------------- | ----------------------------------------------- |
|
|
245
|
+
| `data` | `Signal<TItem[] \| undefined>` | Merged items from all pages |
|
|
246
|
+
| `pages` | `Signal<InfinitePage<TData>[]>` | Array of all pages with status, data, and meta |
|
|
247
|
+
| `loading` | `Signal<boolean>` | True during initial load |
|
|
248
|
+
| `fetching` | `Signal<boolean>` | True during any fetch |
|
|
249
|
+
| `fetchingNext` | `Signal<boolean>` | True while fetching next page |
|
|
250
|
+
| `fetchingPrev` | `Signal<boolean>` | True while fetching previous |
|
|
251
|
+
| `canFetchNext` | `Signal<boolean>` | Whether next page exists |
|
|
252
|
+
| `canFetchPrev` | `Signal<boolean>` | Whether previous page exists |
|
|
253
|
+
| `fetchNext` | `() => Promise<void>` | Fetch the next page |
|
|
254
|
+
| `fetchPrev` | `() => Promise<void>` | Fetch the previous page |
|
|
255
|
+
| `trigger` | `(options?) => Promise<void>` | Trigger fetch with optional new request options |
|
|
256
|
+
| `abort` | `() => void` | Abort current request |
|
|
257
|
+
| `error` | `Signal<TError \| undefined>` | Error if request failed |
|