8000 :fix: fix bugs · vue-use-form/vue-use-form@22512cf · GitHub
[go: up one dir, main page]

Skip to content

Commit 22512cf

Browse files
committed
:fix: fix bugs
1 parent f9bd188 commit 22512cf

File tree

7 files changed

+136
-60
lines changed

7 files changed

+136
-60
lines changed

packages/core/src/logic/creatFormControl.ts

Lines changed: 96 additions & 34 deletions
< F438 tr class="diff-line-row">
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { nextTick, reactive, ref, toRefs, unref } from 'vue'
22
import setWith from 'lodash.setwith'
3+
import toPath from 'lodash.topath'
34
import { VALIDATION_MODE } from '../shared/constant'
45
import {
56
get,
@@ -90,7 +91,21 @@ export function creatFormControl<
9091
fieldName ? get(_formState.errors, fieldName) : _formState.errors
9192

9293
const _removeFormStateError = (fieldName: FieldsKey) => {
93-
unset(_formState.errors, fieldName)
94+
if (isEmptyObject(_formState.errors)) {
95+
return
96+
}
97+
98+
const paths = toPath(fieldName)
99+
100+
if (paths.length !== 1) {
101+
let error: any = _formState.errors
102+
for (const path of paths.slice(0, -1)) {
103+
error = error[path]
104+
}
105+
unset(error, paths.at(-1))
106+
} else {
107+
unset(_formState.errors, fieldName)
108+
}
94109
}
95110

96111
const _setFields = (name: FieldsKey, fieldOptions: Partial<Field>) => {
@@ -102,31 +117,51 @@ export function creatFormControl<
102117
}
103118

104119
const _getDefaultValue = (field: FieldsKey) => {
105-
return _defaultValues[field as string]
120+
return _defaultValues[field]
106121
}
107122

108123
const _setValidating = (isValidating: boolean) =>
109124
_setFormState({ isValidating })
110125

111-
const _getFieldProp = (name: FieldsKey, prop: keyof Field) => {
112-
return get(_fields[name], prop)
126+
const _getFieldDom = (name: FieldsKey) => {
127+
return _fields[name].el.value as FieldElement | undefined
113128
}
114129

115-
const _getFieldDom = (name: FieldsKey) => {
116-
return _getFieldProp(name, 'el') as FieldElement | undefined
130+
const _isDirtyField = (fieldName: FieldsKey) => {
131+
const field = _fields[fieldName]
132+
133+
if (!field) {
134+
return false
135+
}
136+
137+
const inputVal = field.inputValue.value
138+
const defaultVal = _getDefaultValue(fieldName)
139+
const el = field.el.value
140+
141+
if (!isUndefined(defaultVal)) {
142+
if (isRadioOrCheckboxInput(el)) {
143+
return inputVal !== defaultVal && el.checked !== defaultVal
144+
} else {
145+
return inputVal !== defaultVal
146+
}
147+
}
148+
149+
if (isRadioOrCheckboxInput(el)) {
150+
return inputVal !== el.checked
151+
} else {
152+
return inputVal !== ''
153+
}
117154
}
118155

119156
const _getDirtyFields = (handleIsDirty = true) => {
120157
const dirtyFields = {} as TFormState['dirtyFields']
121158

122-
Object.entries(_fields).forEach(([key, val]) => {
123-
if (
124-
val.isDirty ||
125-
(_getDefaultValue(key) &&
126-
val.inputValue.value !== _getDefaultValue(key)) ||
127-
val.inputValue.value !== ''
128-
) {
159+
Object.keys(_fields).forEach((key) => {
160+
if (_isDirtyField(key)) {
129161
set(dirtyFields, key, true)
162+
} else {
163+
unset(dirtyFields, key)
164+
_fields[key].isDirty = false
130165
}
131166
})
132167

@@ -293,6 +328,7 @@ export function creatFormControl<
293328
}
294329

295330
const _onChange = async (name?: FieldsKey) => {
331+
_getDirtyFields()
296332
await trigger(name)
297333

298334
_handleIsValidFields()
@@ -318,13 +354,23 @@ export function creatFormControl<
318354
}
319355

320356
Object.entries(values).forEach(([key, val]) => {
321-
_fields[key].inputValue.value = val
357+
const el = _fields[key].el.value
358+
359+
if (!keepStateOptions.keepDefaultValues) {
360+
_formState.defaultValues[key as keyof TFieldValues] = val
361+
}
362+
if (!keepStateOptions.keepValues) {
363+
_fields[key].inputValue.value = val
364+
}
365+
if (isRadioOrCheckboxInput(el)) {
366+
el.checked = val
367+
}
322368
})
323369

324370
const dirtyFields = _getDirtyFields(false)
325371

326372
if (!keepStateOptions) {
327-
keepStateOptions = {} as any
373+
keepStateOptions = {}
328374
}
329375

330376
_setFormState({
@@ -335,12 +381,13 @@ export function creatFormControl<
335381
? _formState.submitCount
336382
: 0,
337383
errors: keepStateOptions!.keepErrors ? _formState.errors : {},
338-
isDirty: keepStateOptions!.keepDirty
384+
isDirty: keepStateOptions.keepDirtyValues
339385
? _formState.isDirty
340386
: !isEmptyObject(dirtyFields),
341-
dirtyFields: keepStateOptions!.keepDirty
342-
? _formState.dirtyFields
343-
: dirtyFields,
387+
dirtyFields:
388+
keepStateOptions!.keepDirty || keepStateOptions.keepDirtyValues
389+
? _formState.dirtyFields
390+
: dirtyFields,
344391
isSubmitting: false,
345392
isSubmitSuccessful: false,
346393
isValid: keepStateOptions!.keepIsValid ? _formState.isValid : false,
@@ -384,24 +431,33 @@ export function creatFormControl<
384431
}
385432
}
386433

387-
const setError: UseFormSetError<FieldsKey> = (fieldName, error, config) => {
388-
if (!config) {
389-
config = {
390-
shouldFocusError: true,
391-
}
392-
}
434+
const setError: UseFormSetError<FieldsKey> = (
435+
fieldName,
436+
error,
437+
config = { shouldFocusError: true }
438+
) => {
439+
_setFormStateError(fieldName, {
440+
message: '',
441+
...error,
442+
el: _fields[fieldName].el,
443+
} as FieldError)
393444

394-
_setFormStateError(fieldName, error)
445+
_setFormState({
446+
isValid: false,
447+
})
395448

396-
if (config.shouldFocusError)
449+
if (config.shouldFocusError) {
397450
handleValidateError(error, true, _getFieldDom(fieldName))
451+
}
398452
}
399453

400454
const clearErrors: UseFormClearErrors<FieldsKey> = (fieldName) => {
401455
if (isUndefined(fieldName)) {
402456
set(_formState, 'errors', {})
403457
} else {
404-
if (!isArray(fieldName)) fieldName = [fieldName]
458+
if (!isArray(fieldName)) {
459+
fieldName = [fieldName]
460+
}
405461

406462
fieldName.forEach((name) => {
407463
_removeFormStateError(name)
@@ -473,7 +529,9 @@ export function creatFormControl<
473529
fieldName,
474530
options?: RegisterOptions
475531
) => {
476-
if (isUndefined(options)) options = {}
532+
if (isUndefined(options)) {
533+
options = {}
534+
}
477535

478536
let isModelValue = false
479537
let field = get(_fields, fieldName)
@@ -499,8 +557,14 @@ export function creatFormControl<
499557
isUnregistered: false,
500558
el: ref(null),
501559
})
502-
503560
field = get(_fields, fieldName)
561+
562+
nextTick(() => {
563+
const el = field.el.value
564+
if (el instanceof HTMLElement && isRadioOrCheckboxInput(el)) {
565+
el.checked = defaultVal === '' ? false : defaultVal
566+
}
567+
})
504568
}
505569

506570
const addEventListenerToElement = () => {
@@ -509,14 +573,12 @@ export function creatFormControl<
509573
}
510574

511575
const el = getFormEl(field.el)
512-
_setFields(fieldName, { ..._fields[fieldName], el })
576+
_fields[fieldName].el.value = el
513577

514578
if (isRadioOrCheckboxInput(el)) {
515579
set(_defaultValues, fieldName as string, !!defaultVal)
516580
}
517581

518-
set(_defaultValues, fieldName as string, defaultVal)
519-
520582
// bind validate mode
521583
if (isFieldElement(el)) {
522584
if (validationModeBeforeSubmit.isOnBlur) {
@@ -596,7 +658,7 @@ export function creatFormControl<
596658
if (!options.keepValue) {
597659
_setFieldsValue(
598660
fieldName as string,
599-
_defaultValues[fieldName as string] || ''
661+
_defaultValues[fieldName] || ('' as any)
600662
)
601663
}
602664

packages/core/src/logic/validate.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,13 @@ export function handleValidateError(
2020
shouldFocusOnError: boolean,
2121
el?: FieldElement
2222
) {
23-
if (!isFieldElement(el)) return
23+
if (!isFieldElement(el)) {
24+
return
25+
}
2426

25-
if (!isEmptyObject(error) && shouldFocusOnError) el.focus()
27+
if (!isEmptyObject(error) && shouldFocusOnError) {
28+
el.focus()
29+
}
2630
}
2731

2832
export async function validateField(

packages/core/src/types/errors.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1+
import type { Ref } from 'vue'
12
import type { RegisterOptions } from './validator'
23
import type { FieldElement } from './filed'
34

45
export type FieldError = Partial<{
56
type: keyof RegisterOptions | string
67
// types?: MultipleFieldErrors
78
message?: string
8-
ref?: FieldElement
9+
ref?: Ref<FieldElement>
910
}>
1011

11-
export type FieldErrors<TFieldValues> = Partial<Record<keyof TFieldValues, FieldError>>
12+
export type FieldErrors<TFieldValues> = Partial<
13+
Record<keyof TFieldValues, FieldError>
14+
>

packages/core/src/types/filed.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,14 @@ import type { FieldError } from './errors'
44

55
export type FieldValues = Record<string, any>
66

7-
export type FieldElement = HTMLInputElement| HTMLSelectElement | HTMLTextAreaElement
7+
export type FieldElement =
8+
| HTMLInputElement
9+
| HTMLSelectElement
10+
| HTMLTextAreaElement
811

912
export interface Field {
1013
inputValue: Ref
11-
el: FieldElement
14+
el: Ref<FieldElement>
1215
rule: RegisterOptions
1316
isDirty: boolean
1417
isUnregistered: boolean
@@ -21,5 +24,7 @@ export interface FieldState {
2124
error?: FieldError
2225
}
2326

24-
export type Fields<FieldValues extends object, FieldKeys extends keyof FieldValues> = Record<FieldKeys, Field>
25-
27+
export type Fields<
28+
FieldValues extends object,
29+
FieldKeys extends keyof FieldValues
30+
> = Record<FieldKeys, Field>

packages/core/src/types/form.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export type FieldNamesMarkedBoolean<TFieldValues extends FieldValues> = DeepMap<
2222
export interface UseFormProps<TFieldValues extends object> {
2323
mode: Mode
2424
reValidateMode: Exclude<Mode, 'onTouched' | 'all'>
25-
defaultValues: DefaultValues<TFieldValues>
25+
defaultValues: Partial<DefaultValues<TFieldValues>>
2626
resolver: Resolver<TFieldValues>
2727
shouldFocusError: boolean
2828
shouldUnregister: boolean
@@ -186,6 +186,6 @@ export interface FormState<TFieldValues> {
186186
isSubmitting: boolean
187187
isValidating: boolean
188188
isValid: boolean
189-
defaultValues: Partial<DefaultValues<TFieldValues>>
189+
defaultValues: DefaultValues<TFieldValues>
190190
errors: FieldErrors<TFieldValues>
191191
}

packages/core/src/types/utils.ts

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,27 @@
11
import type { Ref } from 'vue'
22

3-
export type FieldPathValue<FieldValues, FiledName extends keyof FieldValues> = FieldValues[FiledName]
3+
export type FieldPathValue<
4+
FieldValues,
5+
FiledName extends keyof FieldValues
6+
> = FieldValues[FiledName]
47

58
declare const $NestedValue: unique symbol
69

710
export type NestedValue<TValue extends object = object> = {
811
[$NestedValue]: never
912
} & TValue
1013

11-
export type DefaultValues<TFieldValues> = UnpackNestedValue<
12-
DeepPartial<TFieldValues>
13-
>
14+
export type DefaultValues<TFieldValues> = {
15+
[K in keyof TFieldValues]?: TFieldValues[K]
16+
}
1417

1518
export type UnpackNestedValue<T> = T extends NestedValue<infer U>
1619
? U
1720
: T extends Date | FileList | File | Blob
18-
? T
19-
: T extends object
20-
? { [K in keyof T]: UnpackNestedValue<T[K]> }
21-
: T
21+
? T
22+
: T extends object
23+
? { [K in keyof T]: UnpackNestedValue<T[K]> }
24+
: T
2225

2326
export type DeepPartial<T> = T extends Date | FileList | File | NestedValue
2427
? T
@@ -31,11 +34,11 @@ export type IsAny<T> = 0 extends 1 & T ? true : false
3134
export type DeepMap<T, TValue> = IsAny<T> extends true
3235
? any
3336
: T extends Date | FileList | File | NestedValue
34-
? TValue
35-
: T extends object
36-
? { [K in keyof T]: DeepMap<NonUndefined<T[K]>, TValue> }
37-
: TValue
37+
? TValue
38+
: T extends object
39+
? { [K in keyof T]: DeepMap<NonUndefined<T[K]>, TValue> }
40+
: TValue
3841

3942
export type MaybeRef<T> = T | Ref<T>
4043

41-
export type IsString<Val> = Val extends string ? Val: never
44+
export type IsString<Val> = Val extends string ? Val : never

packages/core/src/useForm.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1+
import { creatFormControl } from './logic/creatFormControl'
12
import type { UseFormProps } from './types/form'
23
import type { FieldValues } from './types/filed'
34

4-
import { creatFormControl } from './logic/creatFormControl'
5-
65
export function useForm<TFieldValues extends FieldValues = FieldValues>(
7-
props: Partial<UseFormProps<TFieldValues>> = {},
6+
props: Partial<UseFormProps<TFieldValues>> = {}
87
) {
98
props = {
109
mode: 'onSubmit',

0 commit comments

Comments
 (0)
0