294 lines
7.0 KiB
Markdown
294 lines
7.0 KiB
Markdown
# Resource
|
|
|
|
Resource is a feature to manage async data fetching and mutations in your Vue
|
|
frontend. It will fetch, cache and keep data up-to-date from the server.
|
|
|
|
## Basic example
|
|
|
|
Any data that is fetched via a web request is called a resource in jingrow-ui
|
|
terminology. When you are dealing with async data, you are also dealing with
|
|
loading states, error states, refetching etc. In the traditional way of fetching
|
|
data, you have to handle loading states, error states, and refetching yourself.
|
|
|
|
```js
|
|
let data, loading, error
|
|
try {
|
|
data = await fetch('https://jsonplaceholder.typicode.com/posts/1')
|
|
} catch (e) {
|
|
error = e
|
|
}
|
|
// rest of your code
|
|
```
|
|
|
|
The above example is still a very simplified version. You might also need a way
|
|
to reload your data.
|
|
|
|
When you create a resource using the `createResource` function, it will create a
|
|
reactive object with properties like `data`, `loading`, `error`, `reload()` etc.
|
|
|
|
The default request method is `POST`. This can be changed in the `options`
|
|
object.
|
|
|
|
```vue
|
|
<template>
|
|
<Button @click="post.reload()" :loading="post.loading"> Reload </Button>
|
|
<pre>{{ post }}</pre>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { createResource } from 'jingrow-ui'
|
|
let post = createResource({
|
|
url: 'https://jsonplaceholder.typicode.com/posts/1',
|
|
method: 'GET',
|
|
})
|
|
post.fetch()
|
|
</script>
|
|
```
|
|
|
|
## Options API example
|
|
|
|
Resources can also be used in options API style. You need to register the
|
|
`resourcesPlugin` first.
|
|
|
|
**main.js**
|
|
|
|
```js
|
|
import { resourcesPlugin } from 'jingrow-ui'
|
|
app.use(resourcesPlugin)
|
|
```
|
|
|
|
In your `.vue` file, you can declare all your resources under the `resources`
|
|
key as functions. The actual resource object will be available on
|
|
`this.$resources.[name]`. In the following example, `this.$resources.posts` is
|
|
the resource object.
|
|
|
|
**Component.vue**
|
|
|
|
```vue
|
|
<template>
|
|
<pre>{{ $resources.posts }}</pre>
|
|
</template>
|
|
<script>
|
|
export default {
|
|
resources: {
|
|
posts() {
|
|
return {
|
|
url: 'https://jsonplaceholder.typicode.com/posts/1',
|
|
// option to call .fetch() the first time automatically
|
|
auto: true,
|
|
}
|
|
},
|
|
},
|
|
}
|
|
</script>
|
|
```
|
|
|
|
## Caching example
|
|
|
|
Caching is a first-class feature in resources. To cache responses, just define a
|
|
`cache` property in options with a unique global key. Now, the response will
|
|
cached in memory as well as in IndexedDB. If you define another resource in a
|
|
different part of your application with the same cache key, it will reuse the
|
|
cached one.
|
|
|
|
```vue
|
|
<template>
|
|
<Button @click="post.reload()" :loading="post.loading">
|
|
{{ post.fetched ? 'Reload' : 'Fetch data' }}
|
|
</Button>
|
|
<pre>{{ post.data }}</pre>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { createResource } from 'jingrow-ui'
|
|
let post = createResource({
|
|
url: 'https://jsonplaceholder.typicode.com/posts/1',
|
|
cache: 'posts',
|
|
})
|
|
</script>
|
|
```
|
|
|
|
## List of Options and API
|
|
|
|
Here is the list of all options and APIs that are available on a resource.
|
|
|
|
### Options
|
|
|
|
```js
|
|
let post = createResource({
|
|
// partial rest api routes
|
|
url: '/api/posts/1'
|
|
// or full urls
|
|
url: 'https://jsonplaceholder.typicode.com/posts/1',
|
|
|
|
// http method: GET, POST, PUT, DELETE
|
|
method: 'GET',
|
|
|
|
// parameters
|
|
params: {
|
|
id: 1
|
|
},
|
|
// generate params from function
|
|
makeParams() {
|
|
return {
|
|
id: 1
|
|
}
|
|
},
|
|
|
|
// debounce request every 500ms
|
|
debounce: 500,
|
|
|
|
// initial data
|
|
initialData: []
|
|
|
|
// make the first request automatically
|
|
auto: true,
|
|
|
|
// cache key to cache the resource
|
|
// can be a string
|
|
cache: 'post',
|
|
// or an array that can be serialized
|
|
cache: ['post', '1'],
|
|
// you can also pass reactive variable here
|
|
cache: ['post', postId]
|
|
|
|
// events
|
|
// before making the request
|
|
beforeSubmit(params) {
|
|
|
|
},
|
|
// validate parameters before making request
|
|
validate(params) {
|
|
if (!params.id) {
|
|
// return a string message to throw an error
|
|
return 'id is required'
|
|
}
|
|
},
|
|
// error can occur from failed request and validate function
|
|
onError(error) {
|
|
|
|
},
|
|
// on successful response
|
|
onSuccess(data) {
|
|
|
|
},
|
|
// transform data before setting it
|
|
transform(data) {
|
|
for (let d of data) {
|
|
d.open = false
|
|
}
|
|
return data
|
|
},
|
|
})
|
|
```
|
|
|
|
### API
|
|
|
|
```js
|
|
let post = createResource({...})
|
|
|
|
post.data // data returned from request
|
|
post.loading // true when data is being fetched
|
|
post.error // error that occurred from making the request or from validate function
|
|
post.promise // promise object of the request, can be awaited
|
|
post.params // params that were sent for making the request, if using makeParams, the return value is set here
|
|
post.fetched // true when data has been fetched once, stays true after that
|
|
post.previousData // when you call .reload(), previousData is set to current data, and then data is set to new returned data
|
|
|
|
post.fetch() // make the web request (fetch call)
|
|
post.reload() // alias to fetch
|
|
post.submit() // alias to fetch
|
|
|
|
// you can also pass parameters while calling submit
|
|
post.submit({ id: 2 })
|
|
|
|
// reset the state of this resource as a newly created one
|
|
post.reset()
|
|
|
|
// update url and params
|
|
post.update({
|
|
url: '/api/users',
|
|
params: {
|
|
id: 2
|
|
}
|
|
})
|
|
|
|
// override data manually
|
|
post.setData({
|
|
id: 1,
|
|
title: 'test'
|
|
})
|
|
// modify existing data
|
|
post.setData(data => {
|
|
return data.filter(d => d.open)
|
|
})
|
|
```
|
|
|
|
## Jingrow Resource
|
|
|
|
Fetching data from a Jingrow backend is no different from any other REST API
|
|
service.
|
|
|
|
```vue
|
|
<template>
|
|
<Button @click="todos.reload()" :loading="todos.loading"> Reload </Button>
|
|
<pre>{{ todos }}</pre>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { createResource } from 'jingrow-ui'
|
|
let todos = createResource({
|
|
url: '/api/action/jingrow.client.get_list',
|
|
params: {
|
|
pagetype: 'ToDo',
|
|
filters: {
|
|
allocated_to: 'faris@jingrow.com',
|
|
},
|
|
},
|
|
})
|
|
todos.fetch()
|
|
</script>
|
|
```
|
|
|
|
But the response format by Jingrow Framework requires some parsing to be done to
|
|
extract data and errors. Since `jingrow-ui` is built primarily for Jingrow backend
|
|
apps, we can make it understand Jingrow responses.
|
|
|
|
By default, resources use the `request` function exported from `jingrow-ui` which
|
|
is a generic Fetch API wrapper. There is another function `jingrowRequest` which
|
|
is a wrapper for Jingrow REST API calls. To make resources use it, you have to do
|
|
the following:
|
|
|
|
**main.js**
|
|
|
|
```js
|
|
import { setConfig, jingrowRequest } from 'jingrow-ui'
|
|
setConfig('resourceFetcher', jingrowRequest)
|
|
```
|
|
|
|
Now, resources will use `jingrowRequest` for making the web requests. You can
|
|
also drop the `/api/method` part. The returned response will now set the data
|
|
from `message` key and error from `exc`.
|
|
|
|
```vue
|
|
<template>
|
|
<Button @click="post.reload()" :loading="post.loading"> Reload </Button>
|
|
<pre>{{ post }}</pre>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { createResource } from 'jingrow-ui'
|
|
let todos = createResource({
|
|
- url: '/api/action/jingrow.client.get_list',
|
|
+ url: 'jingrow.client.get_list',
|
|
params: {
|
|
pagetype: 'ToDo',
|
|
filters: {
|
|
allocated_to: 'faris@jingrow.com',
|
|
},
|
|
},
|
|
})
|
|
todos.fetch()
|
|
</script>
|
|
```
|