Rewrite client form library to derive state where possible and handle steps
This commit is contained in:
parent
3fa5b3b571
commit
700e36854c
|
@ -1749,8 +1749,12 @@
|
|||
"key": "valid"
|
||||
},
|
||||
{
|
||||
"label": "Step",
|
||||
"key": "step"
|
||||
"label": "Current Step",
|
||||
"key": "currentStep"
|
||||
},
|
||||
{
|
||||
"label": "Current Step Valid",
|
||||
"key": "currentStepValid"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -1776,16 +1780,7 @@
|
|||
"defaultValue": 1,
|
||||
"min": 1
|
||||
}
|
||||
],
|
||||
"context": {
|
||||
"type": "static",
|
||||
"values": [
|
||||
{
|
||||
"label": "Valid",
|
||||
"key": "valid"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"fieldgroup": {
|
||||
"name": "Field Group",
|
||||
|
|
|
@ -42,11 +42,11 @@
|
|||
bind:fieldApi
|
||||
defaultValue={[]}
|
||||
>
|
||||
{#if $fieldState}
|
||||
{#if fieldState}
|
||||
<CoreDropzone
|
||||
value={$fieldState.value}
|
||||
disabled={$fieldState.disabled}
|
||||
error={$fieldState.error}
|
||||
value={fieldState.value}
|
||||
disabled={fieldState.disabled}
|
||||
error={fieldState.error}
|
||||
on:change={e => {
|
||||
fieldApi.setValue(e.detail)
|
||||
}}
|
||||
|
|
|
@ -39,10 +39,10 @@
|
|||
>
|
||||
{#if fieldState}
|
||||
<CoreCheckbox
|
||||
value={$fieldState.value}
|
||||
disabled={$fieldState.disabled}
|
||||
error={$fieldState.error}
|
||||
id={$fieldState.fieldId}
|
||||
value={fieldState.value}
|
||||
disabled={fieldState.disabled}
|
||||
error={fieldState.error}
|
||||
id={fieldState.fieldId}
|
||||
{size}
|
||||
on:change={e => fieldApi.setValue(e.detail)}
|
||||
{text}
|
||||
|
|
|
@ -51,11 +51,11 @@
|
|||
>
|
||||
{#if fieldState}
|
||||
<CoreDatePicker
|
||||
value={$fieldState.value}
|
||||
value={fieldState.value}
|
||||
on:change={e => fieldApi.setValue(e.detail)}
|
||||
disabled={$fieldState.disabled}
|
||||
error={$fieldState.error}
|
||||
id={$fieldState.fieldId}
|
||||
disabled={fieldState.disabled}
|
||||
error={fieldState.error}
|
||||
id={fieldState.fieldId}
|
||||
{enableTime}
|
||||
{placeholder}
|
||||
/>
|
||||
|
|
|
@ -15,7 +15,8 @@
|
|||
|
||||
// Get contexts
|
||||
const formContext = getContext("form")
|
||||
const fieldGroupContext = getContext("fieldGroup")
|
||||
const formStepContext = getContext("form-step")
|
||||
const fieldGroupContext = getContext("field-group")
|
||||
const { styleable } = getContext("sdk")
|
||||
const component = getContext("component")
|
||||
|
||||
|
@ -26,16 +27,20 @@
|
|||
field,
|
||||
defaultValue,
|
||||
disabled,
|
||||
validation
|
||||
validation,
|
||||
formStepContext || 1
|
||||
)
|
||||
|
||||
// Expose field properties to parent component
|
||||
fieldState = formField?.fieldState
|
||||
fieldApi = formField?.fieldApi
|
||||
fieldSchema = formField?.fieldSchema
|
||||
$: fieldState = $formField?.fieldState
|
||||
$: fieldApi = $formField?.fieldApi
|
||||
$: fieldSchema = $formField?.fieldSchema
|
||||
|
||||
// Keep validation rules up to date
|
||||
$: fieldApi?.updateValidation(validation)
|
||||
$: updateValidation(validation)
|
||||
const updateValidation = validation => {
|
||||
fieldApi?.updateValidation(validation)
|
||||
}
|
||||
|
||||
// Extract label position from field group context
|
||||
$: labelPositionClass =
|
||||
|
@ -46,7 +51,7 @@
|
|||
<div class="spectrum-Form-item" use:styleable={$component.styles}>
|
||||
<label
|
||||
class:hidden={!label}
|
||||
for={$fieldState?.fieldId}
|
||||
for={fieldState?.fieldId}
|
||||
class={`spectrum-FieldLabel spectrum-FieldLabel--sizeM spectrum-Form-itemLabel ${labelPositionClass}`}
|
||||
>
|
||||
{label || ""}
|
||||
|
@ -64,8 +69,8 @@
|
|||
/>
|
||||
{:else}
|
||||
<slot />
|
||||
{#if $fieldState.error}
|
||||
<div class="error">{$fieldState.error}</div>
|
||||
{#if fieldState.error}
|
||||
<div class="error">{fieldState.error}</div>
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
const { styleable } = getContext("sdk")
|
||||
const component = getContext("component")
|
||||
setContext("fieldGroup", { labelPosition })
|
||||
setContext("field-group", { labelPosition })
|
||||
</script>
|
||||
|
||||
<div class="wrapper" use:styleable={$component.styles}>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<script>
|
||||
import { getContext } from "svelte"
|
||||
|
||||
const fieldGroupContext = getContext("fieldGroup")
|
||||
const fieldGroupContext = getContext("field-group")
|
||||
</script>
|
||||
|
||||
{#if fieldGroupContext}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script>
|
||||
import { getContext } from "svelte"
|
||||
import { getContext, onMount } from "svelte"
|
||||
import InnerForm from "./InnerForm.svelte"
|
||||
|
||||
export let dataSource
|
||||
|
@ -9,6 +9,11 @@
|
|||
export let actionType = "Create"
|
||||
|
||||
const context = getContext("context")
|
||||
const { API } = getContext("sdk")
|
||||
|
||||
let loaded = false
|
||||
let schema
|
||||
let table
|
||||
|
||||
// Returns the closes data context which isn't a built in context
|
||||
const getInitialValues = (type, dataSource, context) => {
|
||||
|
@ -32,19 +37,48 @@
|
|||
return closestContext
|
||||
}
|
||||
|
||||
// Fetches the form schema from this form's dataSource, if one exists
|
||||
const fetchSchema = async () => {
|
||||
if (!dataSource?.tableId) {
|
||||
schema = {}
|
||||
table = null
|
||||
} else {
|
||||
table = await API.fetchTableDefinition(dataSource?.tableId)
|
||||
if (table) {
|
||||
if (dataSource?.type === "query") {
|
||||
schema = {}
|
||||
const params = table.parameters || []
|
||||
params.forEach(param => {
|
||||
schema[param.name] = { ...param, type: "string" }
|
||||
})
|
||||
} else {
|
||||
schema = table.schema || {}
|
||||
}
|
||||
}
|
||||
}
|
||||
loaded = true
|
||||
}
|
||||
|
||||
$: initialValues = getInitialValues(actionType, dataSource, $context)
|
||||
$: resetKey = JSON.stringify(initialValues)
|
||||
|
||||
// Load the form schema on mount
|
||||
onMount(fetchSchema)
|
||||
</script>
|
||||
|
||||
{#key resetKey}
|
||||
<InnerForm
|
||||
{dataSource}
|
||||
{theme}
|
||||
{size}
|
||||
{disabled}
|
||||
{actionType}
|
||||
{initialValues}
|
||||
>
|
||||
<slot />
|
||||
</InnerForm>
|
||||
{/key}
|
||||
{#if loaded}
|
||||
{#key resetKey}
|
||||
<InnerForm
|
||||
{dataSource}
|
||||
{theme}
|
||||
{size}
|
||||
{disabled}
|
||||
{actionType}
|
||||
{schema}
|
||||
{table}
|
||||
{initialValues}
|
||||
>
|
||||
<slot />
|
||||
</InnerForm>
|
||||
{/key}
|
||||
{/if}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script>
|
||||
import { getContext } from "svelte"
|
||||
import { getContext, setContext } from "svelte"
|
||||
import Placeholder from "../Placeholder.svelte"
|
||||
|
||||
export let step
|
||||
|
@ -8,18 +8,17 @@
|
|||
const component = getContext("component")
|
||||
const formContext = getContext("form")
|
||||
|
||||
// Set form step context so fields know what step they are within
|
||||
setContext("form-step", step || 1)
|
||||
|
||||
$: formState = formContext?.formState
|
||||
$: currentStep = $formState?.currentStep
|
||||
</script>
|
||||
|
||||
{#if !formContext}
|
||||
<Placeholder text="Form steps need to be wrapped in a form" />
|
||||
{:else if step === $formState.step}
|
||||
{:else if step === currentStep}
|
||||
<div use:styleable={$component.styles}>
|
||||
<div>
|
||||
Step {step} is visible!
|
||||
</div>
|
||||
<slot />
|
||||
</div>
|
||||
{:else}
|
||||
<div>hiding step {step}!</div>
|
||||
{/if}
|
||||
|
|
|
@ -1,41 +1,84 @@
|
|||
<script>
|
||||
import { setContext, getContext, onMount } from "svelte"
|
||||
import { writable, get } from "svelte/store"
|
||||
import { setContext, getContext } from "svelte"
|
||||
import { derived, get, writable } from "svelte/store"
|
||||
import { createValidatorFromConstraints } from "./validation"
|
||||
import { generateID } from "../helpers"
|
||||
|
||||
export let dataSource
|
||||
export let disabled = false
|
||||
export let initialValues
|
||||
export let schema
|
||||
export let table
|
||||
|
||||
const component = getContext("component")
|
||||
const { styleable, API, Provider, ActionTypes } = getContext("sdk")
|
||||
const { styleable, Provider, ActionTypes } = getContext("sdk")
|
||||
|
||||
let loaded = false
|
||||
let schema
|
||||
let table
|
||||
let fieldMap = {}
|
||||
|
||||
// Form state contains observable data about the form
|
||||
let fields = []
|
||||
const currentStep = writable(1)
|
||||
const formState = writable({
|
||||
values: initialValues,
|
||||
values: {},
|
||||
errors: {},
|
||||
valid: true,
|
||||
step: 1,
|
||||
currentStep: 1,
|
||||
})
|
||||
|
||||
// Form API contains functions to control the form
|
||||
// Reactive derived stores to derive form state from field array
|
||||
$: values = deriveFieldProperty(fields, f => f.fieldState.value)
|
||||
$: errors = deriveFieldProperty(fields, f => f.fieldState.error)
|
||||
$: valid = !Object.values($errors).some(error => error != null)
|
||||
|
||||
// Derive which fields belong in which steps
|
||||
$: currentStepValid = derived(
|
||||
[currentStep, ...fields],
|
||||
([currentStepValue, ...fieldsValue]) => {
|
||||
return !fieldsValue
|
||||
.filter(f => f.step === currentStepValue)
|
||||
.some(f => f.fieldState.error != null)
|
||||
}
|
||||
)
|
||||
|
||||
// Update form state store from derived stores
|
||||
$: {
|
||||
formState.set({
|
||||
values: $values,
|
||||
errors: $errors,
|
||||
valid,
|
||||
currentStep: $currentStep,
|
||||
})
|
||||
}
|
||||
|
||||
// Generates a derived store from an array of fields, comprised of a map of
|
||||
// extracted values from the field array
|
||||
const deriveFieldProperty = (fieldStores, getProp) => {
|
||||
return derived(fieldStores, fieldValues => {
|
||||
const reducer = (map, field) => ({ ...map, [field.name]: getProp(field) })
|
||||
return fieldValues.reduce(reducer, {})
|
||||
})
|
||||
}
|
||||
|
||||
// Searches the field array for a certain field
|
||||
const getField = name => {
|
||||
return fields.find(field => get(field).name === name)
|
||||
}
|
||||
|
||||
const formApi = {
|
||||
registerField: (
|
||||
field,
|
||||
defaultValue = null,
|
||||
fieldDisabled = false,
|
||||
validationRules
|
||||
validationRules,
|
||||
step = 1
|
||||
) => {
|
||||
if (!field) {
|
||||
return
|
||||
}
|
||||
|
||||
// Skip if we've already registered this field
|
||||
const existingField = getField(field)
|
||||
if (existingField) {
|
||||
return existingField
|
||||
}
|
||||
|
||||
// Auto columns are always disabled
|
||||
const isAutoColumn = !!schema?.[field]?.autocolumn
|
||||
|
||||
|
@ -48,99 +91,79 @@
|
|||
table
|
||||
)
|
||||
|
||||
// Construct field object
|
||||
fieldMap[field] = {
|
||||
fieldState: makeFieldState(
|
||||
field,
|
||||
validator,
|
||||
// Construct field info
|
||||
const fieldInfo = writable({
|
||||
name: field,
|
||||
step: step || 1,
|
||||
fieldState: {
|
||||
fieldId: `id-${generateID()}`,
|
||||
value: initialValues[field] ?? defaultValue,
|
||||
error: null,
|
||||
disabled: disabled || fieldDisabled || isAutoColumn,
|
||||
defaultValue,
|
||||
disabled || fieldDisabled || isAutoColumn
|
||||
),
|
||||
validator,
|
||||
},
|
||||
fieldApi: makeFieldApi(field, defaultValue),
|
||||
fieldSchema: schema?.[field] ?? {},
|
||||
})
|
||||
|
||||
// Add this field
|
||||
fields = [...fields, fieldInfo]
|
||||
|
||||
return fieldInfo
|
||||
},
|
||||
validate: (onlyCurrentStep = false) => {
|
||||
// Validate only the current step if required
|
||||
if (onlyCurrentStep) {
|
||||
const stepFields = fields.filter(f => get(f).step === get(currentStep))
|
||||
for (let field of stepFields) {
|
||||
if (!get(field).fieldApi.validate()) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Set initial value
|
||||
const initialValue = get(fieldMap[field].fieldState).value
|
||||
formState.update(state => ({
|
||||
...state,
|
||||
values: {
|
||||
...state.values,
|
||||
[field]: initialValue,
|
||||
},
|
||||
}))
|
||||
|
||||
return fieldMap[field]
|
||||
},
|
||||
validate: () => {
|
||||
const fields = Object.keys(fieldMap)
|
||||
fields.forEach(field => {
|
||||
const { fieldApi } = fieldMap[field]
|
||||
fieldApi.validate()
|
||||
})
|
||||
return get(formState).valid
|
||||
// Otherwise validate all fields
|
||||
for (let field of fields) {
|
||||
if (!get(field).fieldApi.validate()) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
},
|
||||
clear: () => {
|
||||
const fields = Object.keys(fieldMap)
|
||||
// Clear the form by clearing each individual field
|
||||
fields.forEach(field => {
|
||||
const { fieldApi } = fieldMap[field]
|
||||
fieldApi.clearValue()
|
||||
get(field).fieldApi.clearValue()
|
||||
})
|
||||
},
|
||||
nextStep: () => {
|
||||
formState.update(state => ({
|
||||
...state,
|
||||
step: state.step + 1,
|
||||
}))
|
||||
currentStep.update(step => step + 1)
|
||||
},
|
||||
prevStep: () => {
|
||||
formState.update(state => ({
|
||||
...state,
|
||||
step: Math.max(1, state.step - 1),
|
||||
}))
|
||||
currentStep.update(step => Math.max(1, step - 1))
|
||||
},
|
||||
}
|
||||
|
||||
// Provide both form API and state to children
|
||||
setContext("form", { formApi, formState, dataSource })
|
||||
|
||||
// Action context to pass to children
|
||||
const actions = [
|
||||
{ type: ActionTypes.ValidateForm, callback: formApi.validate },
|
||||
{ type: ActionTypes.ClearForm, callback: formApi.clear },
|
||||
{ type: ActionTypes.NextFormStep, callback: formApi.nextStep },
|
||||
{ type: ActionTypes.PrevFormStep, callback: formApi.prevStep },
|
||||
]
|
||||
|
||||
// Creates an API for a specific field
|
||||
const makeFieldApi = field => {
|
||||
// Sets the value for a certain field and invokes validation
|
||||
const setValue = (value, skipCheck = false) => {
|
||||
const { fieldState } = fieldMap[field]
|
||||
const { validator } = get(fieldState)
|
||||
const fieldInfo = getField(field)
|
||||
const { fieldState } = get(fieldInfo)
|
||||
const { validator } = fieldState
|
||||
|
||||
// Skip if the value is the same
|
||||
if (!skipCheck && get(fieldState).value === value) {
|
||||
if (!skipCheck && fieldState.value === value) {
|
||||
return
|
||||
}
|
||||
|
||||
// Update field state
|
||||
const error = validator ? validator(value) : null
|
||||
fieldState.update(state => {
|
||||
state.value = value
|
||||
state.error = error
|
||||
return state
|
||||
})
|
||||
|
||||
// Update form state
|
||||
formState.update(state => {
|
||||
state.values = { ...state.values, [field]: value }
|
||||
if (error) {
|
||||
state.errors = { ...state.errors, [field]: error }
|
||||
} else {
|
||||
delete state.errors[field]
|
||||
}
|
||||
state.valid = Object.keys(state.errors).length === 0
|
||||
fieldInfo.update(state => {
|
||||
state.fieldState.value = value
|
||||
state.fieldState.error = error
|
||||
return state
|
||||
})
|
||||
|
||||
|
@ -149,30 +172,23 @@
|
|||
|
||||
// Clears the value of a certain field back to the initial value
|
||||
const clearValue = () => {
|
||||
const { fieldState } = fieldMap[field]
|
||||
const { defaultValue } = get(fieldState)
|
||||
const newValue = initialValues[field] ?? defaultValue
|
||||
const fieldInfo = getField(field)
|
||||
const { fieldState } = get(fieldInfo)
|
||||
const newValue = initialValues[field] ?? fieldState.defaultValue
|
||||
|
||||
// Update field state
|
||||
fieldState.update(state => {
|
||||
state.value = newValue
|
||||
state.error = null
|
||||
return state
|
||||
})
|
||||
|
||||
// Update form state
|
||||
formState.update(state => {
|
||||
state.values = { ...state.values, [field]: newValue }
|
||||
delete state.errors[field]
|
||||
state.valid = Object.keys(state.errors).length === 0
|
||||
fieldInfo.update(state => {
|
||||
state.fieldState.value = newValue
|
||||
state.fieldState.error = null
|
||||
return state
|
||||
})
|
||||
}
|
||||
|
||||
// Updates the validator rules for a certain field
|
||||
const updateValidation = validationRules => {
|
||||
const { fieldState } = fieldMap[field]
|
||||
const { value, error } = get(fieldState)
|
||||
const fieldInfo = getField(field)
|
||||
const { fieldState } = get(fieldInfo)
|
||||
const { value, error } = fieldState
|
||||
|
||||
// Create new validator
|
||||
const schemaConstraints = schema?.[field]?.constraints
|
||||
|
@ -184,8 +200,8 @@
|
|||
)
|
||||
|
||||
// Update validator
|
||||
fieldState.update(state => {
|
||||
state.validator = validator
|
||||
fieldInfo.update(state => {
|
||||
state.fieldState.validator = validator
|
||||
return state
|
||||
})
|
||||
|
||||
|
@ -201,63 +217,46 @@
|
|||
clearValue,
|
||||
updateValidation,
|
||||
validate: () => {
|
||||
const { fieldState } = fieldMap[field]
|
||||
setValue(get(fieldState).value, true)
|
||||
// Validate the field by force setting the same value again
|
||||
const { fieldState } = get(getField(field))
|
||||
return setValue(fieldState.value, true)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Creates observable state data about a specific field
|
||||
const makeFieldState = (field, validator, defaultValue, fieldDisabled) => {
|
||||
return writable({
|
||||
field,
|
||||
fieldId: `id-${generateID()}`,
|
||||
value: initialValues[field] ?? defaultValue,
|
||||
error: null,
|
||||
disabled: fieldDisabled,
|
||||
defaultValue,
|
||||
validator,
|
||||
})
|
||||
}
|
||||
// Provide form state and api for full control by children
|
||||
setContext("form", {
|
||||
formState,
|
||||
formApi,
|
||||
|
||||
// Fetches the form schema from this form's dataSource, if one exists
|
||||
const fetchSchema = async () => {
|
||||
if (!dataSource?.tableId) {
|
||||
schema = {}
|
||||
table = null
|
||||
} else {
|
||||
table = await API.fetchTableDefinition(dataSource?.tableId)
|
||||
if (table) {
|
||||
if (dataSource?.type === "query") {
|
||||
schema = {}
|
||||
const params = table.parameters || []
|
||||
params.forEach(param => {
|
||||
schema[param.name] = { ...param, type: "string" }
|
||||
})
|
||||
} else {
|
||||
schema = table.schema || {}
|
||||
}
|
||||
}
|
||||
}
|
||||
loaded = true
|
||||
}
|
||||
// Data source is needed by attachment fields to be able to upload files
|
||||
// to the correct table ID
|
||||
dataSource,
|
||||
})
|
||||
|
||||
// Load the form schema on mount
|
||||
onMount(fetchSchema)
|
||||
// Provide form step context so that forms without any step components
|
||||
// register their fields to step 1
|
||||
setContext("form-step", 1)
|
||||
|
||||
// Action context to pass to children
|
||||
const actions = [
|
||||
{ type: ActionTypes.ValidateForm, callback: formApi.validate },
|
||||
{ type: ActionTypes.ClearForm, callback: formApi.clear },
|
||||
{ type: ActionTypes.NextFormStep, callback: formApi.nextStep },
|
||||
{ type: ActionTypes.PrevFormStep, callback: formApi.prevStep },
|
||||
]
|
||||
</script>
|
||||
|
||||
<Provider
|
||||
{actions}
|
||||
data={{
|
||||
...$formState.values,
|
||||
tableId: dataSource?.tableId,
|
||||
valid: $formState.valid,
|
||||
step: $formState.step,
|
||||
...$values,
|
||||
valid,
|
||||
currentStep: $currentStep,
|
||||
currentStepValid: $currentStepValid,
|
||||
}}
|
||||
>
|
||||
<div use:styleable={$component.styles}>
|
||||
{#if loaded}
|
||||
<slot />
|
||||
{/if}
|
||||
<slot />
|
||||
</div>
|
||||
</Provider>
|
||||
|
|
|
@ -25,11 +25,11 @@
|
|||
>
|
||||
{#if fieldState}
|
||||
<CoreTextArea
|
||||
value={$fieldState.value}
|
||||
value={fieldState.value}
|
||||
on:change={e => fieldApi.setValue(e.detail)}
|
||||
disabled={$fieldState.disabled}
|
||||
error={$fieldState.error}
|
||||
id={$fieldState.fieldId}
|
||||
disabled={fieldState.disabled}
|
||||
error={fieldState.error}
|
||||
id={fieldState.fieldId}
|
||||
{placeholder}
|
||||
/>
|
||||
{/if}
|
||||
|
|
|
@ -77,10 +77,10 @@
|
|||
{#if fieldState}
|
||||
{#if !optionsType || optionsType === "select"}
|
||||
<CoreSelect
|
||||
value={$fieldState.value}
|
||||
id={$fieldState.fieldId}
|
||||
disabled={$fieldState.disabled}
|
||||
error={$fieldState.error}
|
||||
value={fieldState.value}
|
||||
id={fieldState.fieldId}
|
||||
disabled={fieldState.disabled}
|
||||
error={fieldState.error}
|
||||
{options}
|
||||
{placeholder}
|
||||
on:change={e => fieldApi.setValue(e.detail)}
|
||||
|
@ -90,10 +90,10 @@
|
|||
/>
|
||||
{:else if optionsType === "radio"}
|
||||
<CoreRadioGroup
|
||||
value={$fieldState.value}
|
||||
id={$fieldState.fieldId}
|
||||
disabled={$fieldState.disabled}
|
||||
error={$fieldState.error}
|
||||
value={fieldState.value}
|
||||
id={fieldState.fieldId}
|
||||
disabled={fieldState.disabled}
|
||||
error={fieldState.error}
|
||||
{options}
|
||||
on:change={e => fieldApi.setValue(e.detail)}
|
||||
getOptionLabel={flatOptions ? x => x : x => x.label}
|
||||
|
|
|
@ -23,8 +23,8 @@
|
|||
$: linkedTableId = fieldSchema?.tableId
|
||||
$: fetchRows(linkedTableId)
|
||||
$: fetchTable(linkedTableId)
|
||||
$: singleValue = flatten($fieldState?.value)?.[0]
|
||||
$: multiValue = flatten($fieldState?.value) ?? []
|
||||
$: singleValue = flatten(fieldState?.value)?.[0]
|
||||
$: multiValue = flatten(fieldState?.value) ?? []
|
||||
$: component = multiselect ? CoreMultiselect : CoreSelect
|
||||
|
||||
const fetchTable = async id => {
|
||||
|
@ -81,9 +81,9 @@
|
|||
{autocomplete}
|
||||
value={multiselect ? multiValue : singleValue}
|
||||
on:change={multiselect ? multiHandler : singleHandler}
|
||||
id={$fieldState.fieldId}
|
||||
disabled={$fieldState.disabled}
|
||||
error={$fieldState.error}
|
||||
id={fieldState.fieldId}
|
||||
disabled={fieldState.disabled}
|
||||
error={fieldState.error}
|
||||
getOptionLabel={getDisplayName}
|
||||
getOptionValue={option => option._id}
|
||||
{placeholder}
|
||||
|
|
|
@ -26,12 +26,12 @@
|
|||
>
|
||||
{#if fieldState}
|
||||
<CoreTextField
|
||||
updateOnChange={false}
|
||||
value={$fieldState.value}
|
||||
updateOnChange={true}
|
||||
value={fieldState.value}
|
||||
on:change={e => fieldApi.setValue(e.detail)}
|
||||
disabled={$fieldState.disabled}
|
||||
error={$fieldState.error}
|
||||
id={$fieldState.fieldId}
|
||||
disabled={fieldState.disabled}
|
||||
error={fieldState.error}
|
||||
id={fieldState.fieldId}
|
||||
{placeholder}
|
||||
{type}
|
||||
/>
|
||||
|
|
Loading…
Reference in New Issue