usePrecognitionForm
Composable for working with Precognition form instance in your code.
This composable is used to create an instance of a Precognition form that supports both validation and data submission.
We use a type system so you can work with only existing properties of the object. You have to define a Type of Interface for your payload.
Here is a basic sample of form creation:
type MyFormType = {
email: string
password: string
}
const form = usePrecognitionForm<MyFormType>(
'post',
'/api/signup',
{
email: '',
password: '',
},
)
Form data
Fields
You can easily access each field of the form by accessing form.fields.NAME
where NAME
is a key of your form schema.
<input
id="password"
v-model="form.fields.password"
type="password"
@change="form.validate('password')"
>
In case you need the whole payload as a reactive object, you can use just form.fields
value, which returns the complete state.
console.log('Form fields:', form.fields)
Data
To get the value underneath the reactive wrapper, just use form.data()
method, which is also used for form submission under the hood.
const myFormData = form.data()
Since some values may be updated programmatically, you can rely on setData
method to set multiple values at once instead of working with reactive fields
value.
const newDataToAssign = { password: 'random-string' }
form.setData(newDataToAssign)
This keeps existing values and overrides only new keys passed as an argument.
Reset
You can always reset the form or a single field to the original state, which was passed as an argument to usePrecognitionForm
composable.
const form = usePrecognitionForm<MyFormType>(
'post',
'/api/signup',
{
email: 'john@doe.com',
password: '',
},
)
form.setData({ email: 'jane@doe.com' })
console.log(form.fields.email) // jane@doe.com
form.fields.email = 'invalid@email.com'
console.log(form.fields.email) // invalid@email.com
form.reset('email')
console.log(form.fields.email) // john@doe.com
form.reset() // resets all form fields
Errors
Our module takes care of the form error propagation once we have a response from the Laravel API. However, the method of their representation depends on your specific needs.
To retrieve the current state of errors, you may use form.errors
reactive value:
form.validate()
const errors = form.errors
It returns a Record<string, string[]>
map where each field name contains multiple error messages returned from the API.
You can also check if there are any errors at all by checking the value of form.hasErrors
, which is useful for Vue templates:
<div v-if="form.hasErrors">
<!-- Show errors here -->
</div>
In case you need to reset some errors before it gets validated, use forgetError
helper method:
<input
id="avatar"
type="file"
@change="(e) => {
form.avatar = e.target.files[0]
form.forgetError('avatar')
}"
>
Behind the scenes, our module uses setErrors
method to update the form state according to the API response, but you can easily use it in your code as well:
const myErrorsToSet = {
email: [
'Email should contain only one "@" character',
'Email should not contain spaces',
],
password: ['You cannot use emojis in the password'],
}
form.setErrors(myErrorsToSet)
State
While working with a form, you can get the current state details by using processing
and validating
fields. Both values are stored as Ref<boolean>
type.
Processing
equalstrue
if your submit request is in flight state (being sent to the API).Validating
equalstrue
if your validation request is in flight state.
These states are useful if you want to disable Submit/Validate buttons to avoid multiple requests against the API.
<button
:disabled="form.processing"
@click="submit"
>
Submit
</button>
<button
:disabled="form.validating"
@click="validate"
>
Validate
</button>
Validation
The precognition form has the same method to validate a particular field or the whole form at once. Here is an example:
form.validate('email') // validates only email
form.validate(['email', 'password']) // validates both fields
This might be useful if you have a single form separated into several steps (e.g. Installation Wizards, Multi-Stage Signup, etc).
<button
type="button"
@click="form.validate(
['name', 'email', 'phone'],
{
validateFiles: false,
onSuccess: (response: FetchResponse<unknown>) => /* ... */,
onError: (error) => /* ... */,
onValidationError: (response: FetchResponse<unknown>) => /* ... */,
}
)"
>
Next Step
</button>
As you can see in the example above, we also pass an additional argument to validate
method, which contains the following:
validateFiles - flag determines whether we should attach files to validate via API
onSuccess(response: FetchResponse<unknown>) - callback to execute on successful validation response
onError(error: Error | FetchResponse<unknown>) - callback to handle any error thrown by either API or Nuxt itself
onValidationError(response: FetchResponse<unknown>) - callback to handle validation errors only; it will be executed after form errors are propagated
You may want to check a particular field validation state, and there are two simple methods for that:
form.valid(fieldName) - returns true if field is valid and there are no errors
form.invalid(fieldName) - returns true if field is invalid or has not been validated yet
<div v-if="form.invalid('email')">
Error: {{ form.errors.email }}
</div>
Submit form
Once you have all fields validated and ready to be sent to the Laravel API, you should use submit
method.
If you prefer callback-style syntax, feel free to use submit as a Promise:
form
.submit()
.then((response: FetchResponse<unknown>) => console.log('Form submitted', response))
.catch((error: FetchResponse<unknown>) => console.error('Form error', error))
But if you prefer async-await syntax, here is the same behaviour:
try {
const response = await form.submit()
console.log('Form submitted', response)
}
catch (e) {
const response = e as FetchResponse<unknown>
console.error('Form error', response)
}
Now you are ready to use Laravel Precognition with Nuxt! 🚀
Last updated