Allow fields to dynamically update validation rules so that other fields can be referenced
This commit is contained in:
parent
cebfcb280b
commit
99cb7c8789
|
@ -1,7 +1,7 @@
|
||||||
<script>
|
<script>
|
||||||
import Placeholder from "../Placeholder.svelte"
|
import Placeholder from "../Placeholder.svelte"
|
||||||
import FieldGroupFallback from "./FieldGroupFallback.svelte"
|
import FieldGroupFallback from "./FieldGroupFallback.svelte"
|
||||||
import { getContext } from "svelte"
|
import { getContext, onMount } from "svelte"
|
||||||
|
|
||||||
export let label
|
export let label
|
||||||
export let field
|
export let field
|
||||||
|
@ -34,6 +34,9 @@
|
||||||
fieldApi = formField?.fieldApi
|
fieldApi = formField?.fieldApi
|
||||||
fieldSchema = formField?.fieldSchema
|
fieldSchema = formField?.fieldSchema
|
||||||
|
|
||||||
|
// Keep validation rules up to date
|
||||||
|
$: fieldApi?.updateValidation(validation)
|
||||||
|
|
||||||
// Extract label position from field group context
|
// Extract label position from field group context
|
||||||
$: labelPositionClass =
|
$: labelPositionClass =
|
||||||
labelPosition === "above" ? "" : `spectrum-FieldLabel--${labelPosition}`
|
labelPosition === "above" ? "" : `spectrum-FieldLabel--${labelPosition}`
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
|
|
||||||
// Create validation function based on field schema
|
// Create validation function based on field schema
|
||||||
const schemaConstraints = schema?.[field]?.constraints
|
const schemaConstraints = schema?.[field]?.constraints
|
||||||
const validate = createValidatorFromConstraints(
|
const validator = createValidatorFromConstraints(
|
||||||
schemaConstraints,
|
schemaConstraints,
|
||||||
validationRules,
|
validationRules,
|
||||||
field,
|
field,
|
||||||
|
@ -47,10 +47,11 @@
|
||||||
fieldMap[field] = {
|
fieldMap[field] = {
|
||||||
fieldState: makeFieldState(
|
fieldState: makeFieldState(
|
||||||
field,
|
field,
|
||||||
|
validator,
|
||||||
defaultValue,
|
defaultValue,
|
||||||
disabled || fieldDisabled || isAutoColumn
|
disabled || fieldDisabled || isAutoColumn
|
||||||
),
|
),
|
||||||
fieldApi: makeFieldApi(field, defaultValue, validate),
|
fieldApi: makeFieldApi(field, defaultValue),
|
||||||
fieldSchema: schema?.[field] ?? {},
|
fieldSchema: schema?.[field] ?? {},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,9 +94,11 @@
|
||||||
]
|
]
|
||||||
|
|
||||||
// Creates an API for a specific field
|
// Creates an API for a specific field
|
||||||
const makeFieldApi = (field, defaultValue, validate) => {
|
const makeFieldApi = field => {
|
||||||
|
// Sets the value for a certain field and invokes validation
|
||||||
const setValue = (value, skipCheck = false) => {
|
const setValue = (value, skipCheck = false) => {
|
||||||
const { fieldState } = fieldMap[field]
|
const { fieldState } = fieldMap[field]
|
||||||
|
const { defaultValue, validator } = get(fieldState)
|
||||||
|
|
||||||
// Skip if the value is the same
|
// Skip if the value is the same
|
||||||
if (!skipCheck && get(fieldState).value === value) {
|
if (!skipCheck && get(fieldState).value === value) {
|
||||||
|
@ -103,7 +106,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
const newValue = value == null ? defaultValue : value
|
const newValue = value == null ? defaultValue : value
|
||||||
const newError = validate ? validate(newValue) : null
|
const newError = validator ? validator(newValue) : null
|
||||||
|
|
||||||
// Update field state
|
// Update field state
|
||||||
fieldState.update(state => {
|
fieldState.update(state => {
|
||||||
|
@ -127,15 +130,20 @@
|
||||||
return !newError
|
return !newError
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clears the value of a certain field back to the initial value
|
||||||
const clearValue = () => {
|
const clearValue = () => {
|
||||||
const { fieldState } = fieldMap[field]
|
const { fieldState } = fieldMap[field]
|
||||||
|
const { defaultValue } = get(fieldState)
|
||||||
const newValue = initialValues[field] ?? defaultValue
|
const newValue = initialValues[field] ?? defaultValue
|
||||||
|
|
||||||
|
// Update field state
|
||||||
fieldState.update(state => {
|
fieldState.update(state => {
|
||||||
state.value = newValue
|
state.value = newValue
|
||||||
state.error = null
|
state.error = null
|
||||||
return state
|
return state
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Update form state
|
||||||
formState.update(state => {
|
formState.update(state => {
|
||||||
state.values = { ...state.values, [field]: newValue }
|
state.values = { ...state.values, [field]: newValue }
|
||||||
delete state.errors[field]
|
delete state.errors[field]
|
||||||
|
@ -144,9 +152,37 @@
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Updates the validator rules for a certain field
|
||||||
|
const updateValidation = validationRules => {
|
||||||
|
const { fieldState } = fieldMap[field]
|
||||||
|
const { value, error } = get(fieldState)
|
||||||
|
|
||||||
|
// Create new validator
|
||||||
|
const schemaConstraints = schema?.[field]?.constraints
|
||||||
|
const validator = createValidatorFromConstraints(
|
||||||
|
schemaConstraints,
|
||||||
|
validationRules,
|
||||||
|
field,
|
||||||
|
table
|
||||||
|
)
|
||||||
|
|
||||||
|
// Update validator
|
||||||
|
fieldState.update(state => {
|
||||||
|
state.validator = validator
|
||||||
|
return state
|
||||||
|
})
|
||||||
|
|
||||||
|
// If there is currently an error, run the validator again in case
|
||||||
|
// the error should be cleared by the new validation rules
|
||||||
|
if (error) {
|
||||||
|
setValue(value, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
setValue,
|
setValue,
|
||||||
clearValue,
|
clearValue,
|
||||||
|
updateValidation,
|
||||||
validate: () => {
|
validate: () => {
|
||||||
const { fieldState } = fieldMap[field]
|
const { fieldState } = fieldMap[field]
|
||||||
setValue(get(fieldState).value, true)
|
setValue(get(fieldState).value, true)
|
||||||
|
@ -155,13 +191,15 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates observable state data about a specific field
|
// Creates observable state data about a specific field
|
||||||
const makeFieldState = (field, defaultValue, fieldDisabled) => {
|
const makeFieldState = (field, validator, defaultValue, fieldDisabled) => {
|
||||||
return writable({
|
return writable({
|
||||||
field,
|
field,
|
||||||
fieldId: `id-${generateID()}`,
|
fieldId: `id-${generateID()}`,
|
||||||
value: initialValues[field] ?? defaultValue,
|
value: initialValues[field] ?? defaultValue,
|
||||||
error: null,
|
error: null,
|
||||||
disabled: fieldDisabled,
|
disabled: fieldDisabled,
|
||||||
|
defaultValue,
|
||||||
|
validator,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue