TL;DR
Is there a way to load asynchronous data into <FormKitSchema>
?
I'm trying to fetch async data and load it into a FormKit form generated from a JSON schema (<FormKitSchema>
). I can't seem to find an example and I've tried several ways to do it, but haven't had any luck.
I understand the value
property on an input
element will only ever be used when initially rendered, which is cool. However, I can't seem to fetch the data first and then conditionally load the <FormKitSchema>
afterwards (using v-if
did nothing to help). It appears the rendering must be executed with the initial component loading or nothing shows up.
Example: formComponent.vue
(<FormComponent>
)
<template>
<FormKitSchema :schema="schema" :data="asyncData"/>
</template>
<script setup>
import {reactive, ref} from 'vue';
const getData = async () => {
return new Promise((resolve) => {
setTimeout(() => {
resolve({name: "How do I get this into the form???"})
}, 1500)
})
};
const asyncData = reactive({
userData: await getData(), // Using 'await' here seems to prevent the form from ever loading
submit: async (formData, node) => {
console.log("submit: ", {formData, node});
}
})
const schema = [
{
$cmp: 'FormKit',
props: {
type: 'form',
id: 'form',
onSubmit: '$submit',
plugins: '$plugins',
actions: false,
},
children: [
{
$formkit: 'text',
name: 'fullname',
label: '*Full Name',
placeholder: 'Full Name',
value: "$userData.name",
validation: 'required'
},
{
$formkit: 'submit',
label: 'Save',
disabled: '$get(form).state.valid !== true'
}
]
}
]
</script>
Turns out this isn't a problem or issue with FormKit
nor FormKitSchema
. It's an issue with using await
inside Vue's reactive()
function.
In order to use a promise resolution value (i.e. userData: await getData()
) in the initial reactive()
argument object of a component (like in the formComponent.vue
example), the calling/parent component must wrap them in a <Suspense>
tag. Otherwise, Vue appears to simply not render the component at all, which is why there were no errors and nothing showed up.
From the Vue.js docs on Suspense...
A component with async setup() must be nested in a <Suspense> in order to be rendered.
Therefore, the formComponent.vue
code in the question is okay. Just needed to add a <Suspense>
tag to the template anywhere the <FormComponent>
is used. For example...
Example: parentView.vue
<Suspense>
<FormComponent/>
</Suspense>
NOTE: As of this writing, the <Suspense>
element is experimental and may change.