Appearance
Form utils
codecannon apps ship with some helpers to help you build forms more easily.
useForm
The useForm
hook is a helper that helps you manage form state and validation.
For useForm, we won't go into the complete implementation here as it's quite complex, but we'll show you how to use it.
You can always find the complete composable in ui/src/helpers/form.ts
Basic usage
Minimal usage example of the useForm composable:
typescript
import UsersApi from '@/models/User/Api'
import { useForm } from '@/helpers/form'
const { formData, loading } = useForm({
api: () => new UsersApi(),
defaultData: () => ({
email: '',
}),
})
The useForm
hook takes an object with the following properties:
api
: The API class that the form will use to submit data.defaultData
: A function that returns the default form data.
The useForm
composable returns an object with the following properties:
formData
: The form data object.loading
: A boolean that indicates if the form is currently submitting.See also
Editing
If you're editing an existing resource, you can pass the isEdit
and id
properties to the useForm
composable. Doing so will load the entity when the form is created, and will allow you to update the entity using the submit function.
typescript
import UsersApi from '@/models/User/Api'
import { useForm } from '@/helpers/form'
const { formData, loading } = useForm({
api: () => new UsersApi(),
defaultData: () => ({
email: '',
}),
isEdit: () => true,
id: () => 1,
})
- See also
Submitting
To submit the form, you can call the submit
function that the useForm
composable returns. Depending on if isEdit is true, the function will either create or update the entity.
typescript
import UsersApi from '@/models/User/Api'
import { useForm } from '@/helpers/form'
const { formData, loading, submit } = useForm({
api: () => new UsersApi(),
defaultData: () => ({
email: '',
}),
})
const handleSubmit = async () => {
await submit()
}
- See also
Validation
The useForm
composable automatically works with Laravel backend validation.
If the backend returns validation errors, the formErrors
object will be populated with the errors. The keys in the formErrors
object correspond to the form fields, while the value will be the first field error.
You can pass the form errors to the FormInput
commponent to display the errors.
typescript
import UsersApi from '@/models/User/Api'
import { useForm } from '@/helpers/form'
const { formData, loading, formErrors, submit } = useForm({
api: () => new UsersApi(),
defaultData: () => ({
email: '',
}),
})
const handleSubmit = async () => {
await submit()
if (Object.keys(formErrors).length > 0) {
console.log('Form has errors')
}
}
Resetting
You can reset the form data by calling the reset
function that the useForm
composable returns.
If the form is in edit mode, the form data will be reset to the original entity data. If the form is not in edit mode, the form data will be reset to the default data defined in the defaultData
property.
typescript
import UsersApi from '@/models/User/Api'
import { useForm } from '@/helpers/form'
const { formData, loading, reset } = useForm({
api: () => new UsersApi(),
defaultData: () => ({
email: '',
}),
})
const handleReset = () => {
reset()
}
- See also
Removing
If you want to remove an entity, you can call the remove
function that the useForm
composable returns.
The user will be prompted to confirm the removal, and if they confirm, the entity will be removed.
typescript
import UsersApi from '@/models/User/Api'
import { useForm } from '@/helpers/form'
const { formData, loading, remove } = useForm({
api: () => new UsersApi(),
defaultData: () => ({
email: '',
}),
isEdit: () => true,
id: () => 1,
})
const handleRemove = async () => {
await remove()
}
- See also
Redirect protection
If you want to protect the user from accidentally navigating away from the form when they have unsaved changes, you can set the protectNavigation
property to true
(true
is the default state).
When navigation protection is enabled, the user will be prompted to confirm if they want to navigate away from the form when they have unsaved changes.
typescript
import UsersApi from '@/models/User/Api'
import { useForm } from '@/helpers/form'
const { formData, loading, protectNavigation } = useForm({
api: () => new UsersApi(),
defaultData: () => ({
email: '',
}),
})
const handleNavigation = () => {
protectNavigation.value = false
}
- See also
Attaching to other entities
If you want to attach the form to another entity, when the form is submitted you can pass the attachTo
property to the useForm
composable.
typescript
import UsersApi from '@/models/User/Api'
import { useForm } from '@/helpers/form'
const { formData, loading } = useForm({
api: () => new UsersApi(),
defaultData: () => ({
email: '',
}),
attachTo: () => ({
post: { method: 'associate', id: 1 },
}},
})
- See also
Forcing Values
If you want to force a value for a field, you can pass the forceValues
property to the useForm
composable.
This is useful when you want to set a value for a field that is not in the form or hidden in the form.
typescript
import UsersApi from '@/models/User/Api'
import { useForm } from '@/helpers/form'
const { formData, loading } = useForm({
api: () => new UsersApi(),
defaultData: () => ({
email: '',
}),
forceValues: () => ({
apartment_id: 1,
}),
})
- See also
Hooks
The useForm
composable also provides hooks that you can use to perform actions when certain events occur.
Hooks available are:
onStartLoading
- Called when the form enters the loading state.onStopLoading
- Called when the form finishes the loading state.onClose
- Called when the form stops submitting.onCreated
- Called when the form creates a new entity.onUpdated
- Called when the form updates an entity.onDeleted
- Called when the form removes an entity.
typescript
import UsersApi from '@/models/User/Api'
import { useForm } from '@/helpers/form'
const { formData, loading, submit } = useForm({
api: () => new UsersApi(),
defaultData: () => ({
email: '',
}),
onStartLoading: () => {
console.log('Form is loading')
},
onStopLoading: () => {
console.log('Form has stopped loading')
},
onClose: () => {
console.log('Form has closed')
},
onCreated: () => {
console.log('Entity has been created')
},
onUpdated: () => {
console.log('Entity has been updated')
},
onDeleted: () => {
console.log('Entity has been deleted')
},
})