UNPKG

@mmuscat/angular-resource

Version:
298 lines (222 loc) 5.79 kB
# Angular Resource Data fetching library for Angular Composition API. ## Quick Start [Install via NPM](https://www.npmjs.com/package/@mmuscat/angular-resource) ```bash npm install @mmuscat/angular-resource ``` [Install via Yarn](https://yarnpkg.com/package/@mmuscat/angular-resource) ```bash yarn add @mmuscat/angular-resource ``` ### Example Query ```ts function getTodosByUserId() { const http = inject(HttpClient) return function (userId) { return http.get(url, { params: { userId }, }) } } const GetTodosByUserId = new Query(getTodosByUserId) ``` Mutation ```ts function createTodo() { const http = inject(HttpClient) return function (data) { return http.post(url, data) } } const CreateTodo = new Mutation(createTodo, { operator: exhaustAll, }) ``` Usage ```ts function setup() { const userId = use("123") const [createTodoStatus, createTodo] = inject(CreateTodo) const getTodosByUserId = inject(GetTodosByUserId) const todos = getTodosByUserId(userId, { refetch: [createTodo], initialValue: [], }) return { todos, createTodo, createTodoStatus, } } @Component({ template: ` <spinner *ngIf="todos.pending"></spinner> <div *ngIf="todos.error">Something went wrong</div> <todo *ngFor="let todo of todos.value"></todo> <add-todo (save)="createTodo($event)"></create-todo> `, }) export class MyComponent extends ViewDef(setup) {} ``` ## Api Reference ### Query Queries are services created from factory functions that return another function that produces an observable stream. Supports dependency injection. ```ts function myQuery() { const http = inject(HttpClient) return function (params) { return http.get(url, { params, }) } } const MyQuery = new Query(myQuery) ``` Inject the token in a component and create the query params and an initial value. ```ts function setup() { const myQuery = inject(MyQuery) const params = use(Function) const result = myQuery(params, { initialValue: null, }) return { result, } } ``` This returns a `Value` that emits `Resource` notifications. #### QueryConfig ```ts interface QueryConfig { operator?: <T>() => OperatorFunction<Observable<T>, T> // defaults to switchMap } ``` The default `operator` used to **map** higher order observables can be overridden. ```ts const MyQuery = new Query(myQuery, { operator: concatMap, }) ``` #### QueryOptions ```ts interface QueryOptions<T> { initialValue: T refetch?: Observable<any>[] } ``` The query can be configured with `refetch` to pull fresh data whenever another stream emits a value. If `refetch` is given a `Resource` observable, it will wait until it is `done` before it runs the query again. ```ts function setup() { const myQuery = inject(MyQuery) const [mutation, mutate] = inject(MyMutation) const fetch = use(Function) const result = myQuery(fetch, { initialValue: null, refetch: [mutation], }) } ``` ### Caching Queries are memoized by stringifying arguments. Make sure the params passed to queries are serializable to JSON. ```ts function setup() { const myQuery = inject(MyQuery) const fetch = use(Function) const result = myQuery(fetch, { initialValue: null }) fetch([1, 2, 3]) // stringified to "[1, 2, 3]" to use as cache key } ``` ### Mutation Mutations are services created from factory functions that return another function that produces an observable stream. ```ts function myMutation() { const http = inject(HttpClient) return function (params) { return http.post(url, params) } } const MyMutation = new Mutation(myMutation) ``` #### MutationConfig ```ts interface MutationConfig { operator?: <T>() => OperatorFunction<Observable<T>, T> // defaults to exhaust } ``` The default `operator` used to **flatten** higher order observables can be overridden. ```ts const MyMutation = new Mutation(myMutation, { operator: concat, }) ``` **Returning mutation from a `ViewDef`** Use the array destructure pattern to obtain an `Emitter` that can be used to trigger the mutation outside the `ViewDef` factory. ```ts function setup() { const [mutation, mutate] = inject(MyMutation) return { mutation, // mutation status mutate, // trigger mutation } } @Component({ template: ` <spinner *ngIf="mutation.pending"></spinner> <button (click)="mutate(params)">Mutate</button> `, }) export class MyComponent extends ViewDef(setup) {} ``` ### Resource Interface that represents the state of a `Query` or `Mutation` ```ts interface Resource<T> { value: T error: unknown pending: boolean done: boolean } ``` `pending` is true if there are any active queries or mutations in the queue. `done` is true when there are no more pending transactions, until the next request is made. `error` is set when an error is caught and resets when a new request is made. ### cancel Cancel pending queries ```ts const getTodosByUserId = inject(GetTodosByUserId) const todos = getTodosByUserId(userId) cancel(todos) ``` Cancel pending mutations ```ts const createTodo = inject(CreateTodo) createTodo(todo) cancel(createTodo) ``` ### invalidate Invalidate a single query ```ts const getTodosByUserId = inject(GetTodosByUserId) const todos = getTodosByUserId(userId) invalidate(todos) ``` Invalidate a single query with specific arguments ```ts const getTodosByUserId = inject(GetTodosByUserId) const todos = getTodosByUserId(userId) invalidate(todos, "123") ``` Invalidate all queries by injection token ```ts const getTodosByUserId = inject(GetTodosByUserId) const todos = getTodosByUserId(userId) invalidate(GetTodosByUserId) ```