Appearance
useUpdater
Composable
ts
import { useUpdater } from '@vuemodel/core'
import { Post } from '@vuemodel/sample-data'
const postId = ref('1')
const postUpdater = useUpdater(Post, { id: postId })
postUpdater.form.value.title = 'New Title'
postUpdater.update()
WARNING
It may be tempting to destructure useUpdater (const { form } = useUpdater(Post)
). We don't recommend this. Destructuring blurs the context, and makes it difficult to manage variable name clashes.
The Form
useUpdater
comes with a form that you can use!
ts
const postId = ref('1')
const postUpdater = useUpdater(Post, { id: postId })
postUpdater.form.value.title = 'New Title'
postUpdater.update()
We can also use updater.makeForm()
to prepopulate the form.
When the id
changes, we usually want the form to change too so that the form always matches the id. For that, we can set immediatelyMakeForm
to true
.
How cool is that? And you may notice this works, even if the record we want to update isn't in the store yet!
How Making The Form Works
makeForm
has two ways it tries to populate the form:
- It checks if the record we want to update is already in the store. If it exists, we use that record to populate the form.
- If the records is not in the store, it attempts to find it on the backend. When found on the backend, it uses that found record to populate the store.
This is awesome, because it means all you have to do is call makeForm()
- or set immediatelyMakeForm: true
- and it will populate the form as quickly as it can!
And if we ever need to "refresh" the form, we can simply call makeForm()
again.
INFO
To find the record on the backend, we actually use useFinder
under the hood! We can access this finder via updater.makeFormFinder
. This might be useful if we want to display errors encountered when finding the resource.
Update Signatures
There are a few ways to provide useUpdater
with a form and id. We already showed you how to use updater.form.value
in the above examples. Here are the other ways:
Pass the id
as a parameter
ts
updater.update('1')
Pass the id
and form
as a parameter:
ts
updater.update('1', { title: 'VueModel Is Your Friend!' })
Pass the form
as a parameter:
ts
const postId = ref('1')
const postUpdater = useUpdater(Post, { id: postId })
postUpdater.update({ title: 'VueModel Is Your Friend!' })
Pass the form
, with an id in it, as a parameter. useUpdater
is smart enough to discover the id by looking at the form.
ts
updater.update({ id: '1', title: 'VueModel Is Your Friend!' })
We recommend trying to get most (if not all) your form data into updater.form.value
. These other ways of updating, are a convenience to help cover edge cases.
Form Merging Precedence
As detailed above, there are 2 ways to include form data:
- modifying
updater.form.value
- passing a form to
updater.update(form)
VueModel uses a sensible precedence when merging the form:
updater.form.value
<- updater.update(form)
record
ts
const postUpdater = useUpdater(Post, { id: '1' })
await postUpdater.update({ title: 'My Blog Title' })
console.log(postUpdater.record.value)
When accessing updater.record.value
, we're pulling it out of the store. This is good news! It means any changes to the record in other parts of our application will be reflected when using updater.record.value
Note that when we set optimistic: true
, the record is inserted into the store before the request is successful. This can help make our app responsive, at the cost of a "dishonest UI".
response
ts
const postUpdater = useUpdater(Post, { id: '3' })
await postUpdater.update({ title: 'My Blog Title' })
console.log(postUpdater.response.value)
WARNING
response.value
does NOT return data from the store. Prefer record.value
if you want a value that's responsive to other changes in your app.
The response object is mostly for covering edge cases (like accessing data that didn't end up in the store). It's unlikely you'll need to use it.
persist
ts
const postUpdater = useUpdater(Post, {
id: '3',
persist: false
})
We can use persist: false
to skip persiting the record to the store. In such a scenario, we would need to access the record via response.value
.
updating
ts
const postUpdater = useUpdater(Post, { id: '1' })
postUpdater.update()
console.log(postUpdater.updating.value) // '1'
updating
is not a boolean, it's the primary key of the record being updated.
You'll often find yourself in situations where knowing if updating
is true, isn't enough. For that reason, we decided to make updating
the id of the record being updated.
INFO
Feel free to coerce updating
to a boolean (as we do in many of these examples). You may need to do this at times to satisfy TypeScript:
ts
!!updater.updating.value
Updating: false
makingForm
ts
const postUpdater = useUpdater(Post, { id: '3' })
postUpdater.makeForm()
console.log(postUpdater.makingForm.value) // '3'
Similar to updating.value
, makingForm.value
equals the ID of the form currently being made. This is useful if you want to disable/hide the form while it's being populated.
Auto Update
ts
const postUpdater = useUpdater(Post, {
id: '1',
autoUpdate: true,
// autoUpdateDebounce: 250,
})
If you like, VueModel can watch your form and automatically update when changes occur. Feel free to set your own debouncer with the autoUpdateDebounce
option.
TIP
Combining autoUpdate: true
with optimistic: true
can create a snappy experience for your app!
optimistic
ts
const postUpdater = useUpdater(Post, {
id: '1',
optimistic: true,
})
An "optimistic" UI assumes success before the request is complete. We probably don't want to use it everywhere in our app, yet in some situations it creates a wonderful user experience!
Trello is a great example of an optimistic UI. When cards are moved and text changed, the UI updates instantly before the data is synced with the backend.
Notice in the example below, the record updates immediately while the "update" spinner is still turning!
If the update fails, the record is reverted to it's original value in the store!
activeRequests
Sometimes, the app might be updating more than one record at the same time. For example, if the UI allows users to start updating a second record before the first request is complete.
When more than one request is active:
response.value
is equal to the latest responserecord.value
is found using the ID of the latest successful response- all active requests are available via
activeRequests.value
Validation Errors
To go deeper on handling errors, checkout handling errors.
We have an example below of how this work with an update form:
INFO
If you'd like to do frontend validation, we recommend VeeValidate. If in the future, VueModel decides to tackle validation, it will likely use VeeValidate under the hood.