Skip to content

Commit b8b74a0

Browse files
zAlweNy26romhml
andauthored
feat(Form): support error RegExp in exposed methods (#4608)
Co-authored-by: Romain Hamel <[email protected]>
1 parent 9f3bc9e commit b8b74a0

File tree

3 files changed

+80
-9
lines changed

3 files changed

+80
-9
lines changed

docs/content/3.components/form.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -201,9 +201,9 @@ This will give you access to the following:
201201
| ---- | ---- |
202202
| `submit()`{lang="ts-type"} | `Promise<void>`{lang="ts-type"} <br> <div class="text-toned mt-1"><p>Triggers form submission.</p> |
203203
| `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> |
204-
| `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> |
205-
| `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> |
206-
| `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> |
204+
| `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> |
205+
| `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> |
206+
| `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> |
207207
| `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> |
208208
| `disabled`{lang="ts-type"} | `Ref<boolean>`{lang="ts-type"} |
209209
| `dirty`{lang="ts-type"} | `Ref<boolean>`{lang="ts-type"} `true` if at least one form field has been updated by the user.|

src/runtime/components/Form.vue

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -269,10 +269,10 @@ defineExpose<Form<S>>({
269269
validate: _validate,
270270
errors,
271271
272-
setErrors(errs: FormError[], name?: keyof I) {
272+
setErrors(errs: FormError[], name?: keyof I | RegExp) {
273273
if (name) {
274274
errors.value = errors.value
275-
.filter(error => error.name !== name)
275+
.filter(err => name instanceof RegExp ? !(err.name && name.test(err.name)) : err.name !== name)
276276
.concat(resolveErrorIds(errs))
277277
} else {
278278
errors.value = resolveErrorIds(errs)
@@ -283,16 +283,16 @@ defineExpose<Form<S>>({
283283
await onSubmitWrapper(new Event('submit'))
284284
},
285285
286-
getErrors(name?: keyof I) {
286+
getErrors(name?: keyof I | RegExp) {
287287
if (name) {
288-
return errors.value.filter(err => err.name === name)
288+
return errors.value.filter(err => name instanceof RegExp ? err.name && name.test(err.name) : err.name === name)
289289
}
290290
return errors.value
291291
},
292292
293-
clear(name?: string) {
293+
clear(name?: keyof I | RegExp) {
294294
if (name) {
295-
errors.value = errors.value.filter(err => err.name !== name)
295+
errors.value = errors.value.filter(err => name instanceof RegExp ? !(err.name && name.test(err.name)) : err.name !== name)
296296
} else {
297297
errors.value = []
298298
}

test/components/Form.spec.ts

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,24 @@ describe('Form', () => {
190190
expect(passwordField.text()).toBe('')
191191
})
192192

193+
test('setErrors with regex works', async () => {
194+
form.value.setErrors([{ id: 'emailInput', name: 'email', message: 'this is an error' }])
195+
196+
expect(form.value.errors).toMatchObject([{ id: 'emailInput', name: 'email', message: 'this is an error' }])
197+
198+
form.value.setErrors([{ id: 'passwordInput', name: 'password', message: 'this is another error' }], /email/)
199+
200+
expect(form.value.errors).toMatchObject([{ id: 'passwordInput', name: 'password', message: 'this is another error' }])
201+
202+
await nextTick()
203+
204+
const emailField = wrapper.find('#emailField')
205+
expect(emailField.text()).toBe('')
206+
207+
const passwordField = wrapper.find('#passwordField')
208+
expect(passwordField.text()).toBe('this is another error')
209+
})
210+
193211
test('clear works', async () => {
194212
form.value.setErrors([{
195213
id: 'emailInput',
@@ -201,13 +219,57 @@ describe('Form', () => {
201219

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

222+
await flushPromises()
223+
204224
const emailField = wrapper.find('#emailField')
205225
expect(emailField.text()).toBe('')
206226

207227
const passwordField = wrapper.find('#passwordField')
208228
expect(passwordField.text()).toBe('')
209229
})
210230

231+
test('clear with name works', async () => {
232+
form.value.setErrors([
233+
{ id: 'emailInput', name: 'email', message: 'this is an error' },
234+
{ id: 'passwordInput', name: 'password', message: 'this is another error' }
235+
])
236+
237+
form.value.clear('email')
238+
239+
expect(form.value.errors).toMatchObject([
240+
{ id: 'passwordInput', name: 'password', message: 'this is another error' }
241+
])
242+
243+
await nextTick()
244+
245+
const emailField = wrapper.find('#emailField')
246+
expect(emailField.text()).toBe('')
247+
248+
const passwordField = wrapper.find('#passwordField')
249+
expect(passwordField.text()).toBe('this is another error')
250+
})
251+
252+
test('clear with regex works', async () => {
253+
form.value.setErrors([
254+
{ id: 'emailInput', name: 'email', message: 'this is an error' },
255+
{ id: 'passwordInput', name: 'password', message: 'this is another error' }
256+
])
257+
258+
form.value.clear(/email/)
259+
260+
expect(form.value.errors).toMatchObject([
261+
{ id: 'passwordInput', name: 'password', message: 'this is another error' }
262+
])
263+
264+
await nextTick()
265+
266+
const emailField = wrapper.find('#emailField')
267+
expect(emailField.text()).toBe('')
268+
269+
const passwordField = wrapper.find('#passwordField')
270+
expect(passwordField.text()).toBe('this is another error')
271+
})
272+
211273
test('submit error works', async () => {
212274
await form.value.submit()
213275

@@ -272,6 +334,15 @@ describe('Form', () => {
272334
])
273335
})
274336

337+
test('getErrors with regex works', async () => {
338+
await form.value.submit()
339+
const errors = form.value.getErrors(/email/)
340+
341+
expect(errors).toMatchObject([
342+
{ id: 'emailInput', name: 'email', message: 'Invalid input: expected string, received undefined' }
343+
])
344+
})
345+
275346
test('touchedFields works', async () => {
276347
const emailInput = wrapper.find('#emailInput')
277348

0 commit comments

Comments
 (0)