Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions docs/content/3.components/form.md
Original file line number Diff line number Diff line change
Expand Up @@ -201,9 +201,9 @@ This will give you access to the following:
| ---- | ---- |
| `submit()`{lang="ts-type"} | `Promise<void>`{lang="ts-type"} <br> <div class="text-toned mt-1"><p>Triggers form submission.</p> |
| `validate(opts: { name?: keyof T \| (keyof T)[], silent?: boolean, nested?: boolean, transform?: boolean })`{lang="ts-type"} | `Promise<T>`{lang="ts-type"} <br> <div class="text-toned mt-1"><p>Triggers form validation. Will raise any errors unless `opts.silent` is set to true.</p> |
| `clear(path?: keyof T)`{lang="ts-type"} | `void` <br> <div class="text-toned mt-1"><p>Clears form errors associated with a specific path. If no path is provided, clears all form errors.</p> |
| `getErrors(path?: keyof T)`{lang="ts-type"} | `FormError[]`{lang="ts-type"} <br> <div class="text-toned mt-1"><p>Retrieves form errors associated with a specific path. If no path is provided, returns all form errors.</p></div> |
| `setErrors(errors: FormError[], name?: keyof T)`{lang="ts-type"} | `void` <br> <div class="text-toned mt-1"><p>Sets form errors for a given path. If no path is provided, overrides all errors.</p> |
| `clear(path?: keyof T | RegExp)`{lang="ts-type"} | `void` <br> <div class="text-toned mt-1"><p>Clears form errors associated with a specific path. If no path is provided, clears all form errors.</p> |
| `getErrors(path?: keyof T | RegExp)`{lang="ts-type"} | `FormError[]`{lang="ts-type"} <br> <div class="text-toned mt-1"><p>Retrieves form errors associated with a specific path. If no path is provided, returns all form errors.</p></div> |
| `setErrors(errors: FormError[], name?: keyof T | RegExp)`{lang="ts-type"} | `void` <br> <div class="text-toned mt-1"><p>Sets form errors for a given path. If no path is provided, overrides all errors.</p> |
| `errors`{lang="ts-type"} | `Ref<FormError[]>`{lang="ts-type"} <br> <div class="text-toned mt-1"><p>A reference to the array containing validation errors. Use this to access or manipulate the error information.</p> |
| `disabled`{lang="ts-type"} | `Ref<boolean>`{lang="ts-type"} |
| `dirty`{lang="ts-type"} | `Ref<boolean>`{lang="ts-type"} `true` if at least one form field has been updated by the user.|
Expand Down
12 changes: 6 additions & 6 deletions src/runtime/components/Form.vue
Original file line number Diff line number Diff line change
Expand Up @@ -269,10 +269,10 @@ defineExpose<Form<S>>({
validate: _validate,
errors,

setErrors(errs: FormError[], name?: keyof I) {
setErrors(errs: FormError[], name?: keyof I | RegExp) {
if (name) {
errors.value = errors.value
.filter(error => error.name !== name)
.filter(err => name instanceof RegExp ? !(err.name && name.test(err.name)) : err.name !== name)
.concat(resolveErrorIds(errs))
} else {
errors.value = resolveErrorIds(errs)
Expand All @@ -283,16 +283,16 @@ defineExpose<Form<S>>({
await onSubmitWrapper(new Event('submit'))
},

getErrors(name?: keyof I) {
getErrors(name?: keyof I | RegExp) {
if (name) {
return errors.value.filter(err => err.name === name)
return errors.value.filter(err => name instanceof RegExp ? err.name && name.test(err.name) : err.name === name)
}
return errors.value
},

clear(name?: string) {
clear(name?: string | RegExp) {
if (name) {
errors.value = errors.value.filter(err => err.name !== name)
errors.value = errors.value.filter(err => name instanceof RegExp ? !(err.name && name.test(err.name)) : err.name !== name)
} else {
errors.value = []
}
Expand Down
71 changes: 71 additions & 0 deletions test/components/Form.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,24 @@ describe('Form', () => {
expect(passwordField.text()).toBe('')
})

test('setErrors with regex works', async () => {
form.value.setErrors([{ id: 'emailInput', name: 'email', message: 'this is an error' }])

expect(form.value.errors).toMatchObject([{ id: 'emailInput', name: 'email', message: 'this is an error' }])

form.value.setErrors([{ id: 'passwordInput', name: 'password', message: 'this is another error' }], /email/)

expect(form.value.errors).toMatchObject([{ id: 'passwordInput', name: 'password', message: 'this is another error' }])

await nextTick()

const emailField = wrapper.find('#emailField')
expect(emailField.text()).toBe('')

const passwordField = wrapper.find('#passwordField')
expect(passwordField.text()).toBe('this is another error')
})

test('clear works', async () => {
form.value.setErrors([{
id: 'emailInput',
Expand All @@ -201,13 +219,57 @@ describe('Form', () => {

expect(form.value.errors).toMatchObject([])

await flushPromises()

const emailField = wrapper.find('#emailField')
expect(emailField.text()).toBe('')

const passwordField = wrapper.find('#passwordField')
expect(passwordField.text()).toBe('')
})

test('clear with name works', async () => {
form.value.setErrors([
{ id: 'emailInput', name: 'email', message: 'this is an error' },
{ id: 'passwordInput', name: 'password', message: 'this is another error' }
])

form.value.clear('email')

expect(form.value.errors).toMatchObject([
{ id: 'passwordInput', name: 'password', message: 'this is another error' }
])

await nextTick()

const emailField = wrapper.find('#emailField')
expect(emailField.text()).toBe('')

const passwordField = wrapper.find('#passwordField')
expect(passwordField.text()).toBe('this is another error')
})

test('clear with regex works', async () => {
form.value.setErrors([
{ id: 'emailInput', name: 'email', message: 'this is an error' },
{ id: 'passwordInput', name: 'password', message: 'this is another error' }
])

form.value.clear(/email/)

expect(form.value.errors).toMatchObject([
{ id: 'passwordInput', name: 'password', message: 'this is another error' }
])

await nextTick()

const emailField = wrapper.find('#emailField')
expect(emailField.text()).toBe('')

const passwordField = wrapper.find('#passwordField')
expect(passwordField.text()).toBe('this is another error')
})

test('submit error works', async () => {
await form.value.submit()

Expand Down Expand Up @@ -272,6 +334,15 @@ describe('Form', () => {
])
})

test('getErrors with regex works', async () => {
await form.value.submit()
const errors = form.value.getErrors(/email/)

expect(errors).toMatchObject([
{ id: 'emailInput', name: 'email', message: 'Invalid input: expected string, received undefined' }
])
})

test('touchedFields works', async () => {
const emailInput = wrapper.find('#emailInput')

Expand Down