Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
54 changes: 27 additions & 27 deletions packages/form-core/src/FieldApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
import { defaultFieldMeta } from './metaHelper'
import {
determineFieldLevelErrorSourceAndValue,
evaluate,
getAsyncValidatorArray,
getBy,
getSyncValidatorArray,
Expand Down Expand Up @@ -1052,7 +1053,7 @@ export class FieldApi<
/**
* The field name.
*/
name!: DeepKeys<TParentData>
name: TName
/**
* The field options.
*/
Expand Down Expand Up @@ -1151,8 +1152,10 @@ export class FieldApi<
TParentSubmitMeta
>,
) {
this.form = opts.form as never
this.name = opts.name as never
this.form = opts.form
this.name = opts.name
this.options = opts

this.timeoutIds = {
validations: {} as Record<ValidationCause, never>,
listeners: {} as Record<ListenerCause, never>,
Expand All @@ -1162,12 +1165,21 @@ export class FieldApi<
this.store = new Derived({
deps: [this.form.store],
fn: () => {
const value = this.form.getFieldValue(this.name)
const meta = this.form.getFieldMeta(this.name) ?? {
...defaultFieldMeta,
...opts.defaultMeta,
}

let value = this.form.getFieldValue(this.name)
if (
!meta.isTouched &&
(value as unknown) === undefined &&
this.options.defaultValue !== undefined &&
!evaluate(value, this.options.defaultValue)
) {
value = this.options.defaultValue
}

return {
value,
meta,
Expand Down Expand Up @@ -1196,8 +1208,6 @@ export class FieldApi<
>
},
})

this.options = opts as never
}

/**
Expand Down Expand Up @@ -1232,8 +1242,8 @@ export class FieldApi<
mount = () => {
const cleanup = this.store.mount()

if ((this.options.defaultValue as unknown) !== undefined) {
this.form.setFieldValue(this.name, this.options.defaultValue as never, {
if (this.options.defaultValue !== undefined && !this.getMeta().isTouched) {
this.form.setFieldValue(this.name, this.options.defaultValue, {
dontUpdateMeta: true,
})
}
Expand Down Expand Up @@ -1309,33 +1319,23 @@ export class FieldApi<
TParentSubmitMeta
>,
) => {
this.options = opts as never

const nameHasChanged = this.name !== opts.name
this.options = opts
this.name = opts.name

// Default Value
if ((this.state.value as unknown) === undefined) {
const formDefault = getBy(opts.form.options.defaultValues, opts.name)

const defaultValue = (opts.defaultValue as unknown) ?? formDefault

// The name is dynamic in array fields. It changes when the user performs operations like removing or reordering.
// In this case, we don't want to force a default value if the store managed to find an existing value.
if (nameHasChanged) {
this.setValue((val) => (val as unknown) || defaultValue, {
dontUpdateMeta: true,
})
} else if (defaultValue !== undefined) {
this.setValue(defaultValue as never, {
if (!this.state.meta.isTouched && this.options.defaultValue !== undefined) {
const formField = this.form.getFieldValue(this.name)
if (!evaluate(formField, opts.defaultValue)) {
this.form.setFieldValue(this.name, opts.defaultValue as never, {
dontUpdateMeta: true,
dontValidate: true,
dontRunListeners: true,
})
}
}

// Default Meta
if (this.form.getFieldMeta(this.name) === undefined) {
this.setMeta(this.state.meta)
if (!this.form.getFieldMeta(this.name)) {
this.form.setFieldMeta(this.name, this.state.meta)
}
}

Expand Down
20 changes: 9 additions & 11 deletions packages/form-core/src/FormApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1062,20 +1062,18 @@ export class FormApi<
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
fieldErrors = Object.values(currBaseMeta.errorMap ?? {}).filter(
(val) => val !== undefined,
) as never
)

// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
const fieldInstance = this.getFieldInfo(fieldName)?.instance

if (fieldInstance && !fieldInstance.options.disableErrorFlat) {
fieldErrors = (fieldErrors as undefined | string[])?.flat(
1,
) as never
fieldErrors = fieldErrors.flat(1)
}
}

// As primitives, we don't need to aggressively persist the same referential value for performance reasons
const isFieldValid = !isNonEmptyArray(fieldErrors ?? [])
const isFieldValid = !isNonEmptyArray(fieldErrors)
const isFieldPristine = !currBaseMeta.isDirty
const isDefaultValue =
evaluate(
Expand Down Expand Up @@ -1103,11 +1101,11 @@ export class FormApi<

fieldMeta[fieldName] = {
...currBaseMeta,
errors: fieldErrors,
errors: fieldErrors ?? [],
isPristine: isFieldPristine,
isValid: isFieldValid,
isDefaultValue: isDefaultValue,
} as AnyFieldMeta
} satisfies AnyFieldMeta as AnyFieldMeta
}

if (!Object.keys(currBaseStore.fieldMetaBase).length) return fieldMeta
Expand Down Expand Up @@ -2325,7 +2323,7 @@ export class FormApi<
}

// Shift down all meta after validating to make sure the new field has been mounted
metaHelper(this).handleArrayFieldMetaShift(field, index, 'insert')
metaHelper(this).handleArrayInsert(field, index)

if (!dontValidate) {
await this.validateArrayFieldsStartingFrom(field, index, 'change')
Expand Down Expand Up @@ -2386,7 +2384,7 @@ export class FormApi<
)

// Shift up all meta
metaHelper(this).handleArrayFieldMetaShift(field, index, 'remove')
metaHelper(this).handleArrayRemove(field, index)

if (lastIndex !== null) {
const start = `${field}[${lastIndex}]`
Expand Down Expand Up @@ -2421,7 +2419,7 @@ export class FormApi<
)

// Swap meta
metaHelper(this).handleArrayFieldMetaShift(field, index1, 'swap', index2)
metaHelper(this).handleArraySwap(field, index1, index2)

const dontValidate = options?.dontValidate ?? false
if (!dontValidate) {
Expand Down Expand Up @@ -2453,7 +2451,7 @@ export class FormApi<
)

// Move meta between index1 and index2
metaHelper(this).handleArrayFieldMetaShift(field, index1, 'move', index2)
metaHelper(this).handleArrayMove(field, index1, index2)

const dontValidate = options?.dontValidate ?? false
if (!dontValidate) {
Expand Down
Loading
Loading