sveltekit-superforms
sveltekit-superforms copied to clipboard
Using superForm with $derived
- [x] Before posting an issue, read the FAQ and search the previous issues.
Description I tried retuning multiple superforms in an array, but I could not use it in the frontend. The only convenient way was to destructure each superform in the each tag but svelte doesn't support "declaring" stores out of the top-level of the component
If applicable, a MRE https://www.sveltelab.dev/9tdm9ul193m3tz5
It didn't occur to me to extract the form into a separate component 🤦 So this would work
{#each superforms as superform}
<Comp {superform} />
{/each}
Closing.
I'm reopening this issue because I encountered a problem
When I write this code
<script>
const superforms = data.my_forms.map((form) =>
superForm(form, {
dataType: 'json'
})
);
</script>
{#each superforms as superform (superform.formId)}
<ConditionItem {superform} />
{/each}
It works well but when a new form is added, then that's where I run into a problem
If I try to use $derived
const superforms = $derived(
data.condition_forms.map((form) =>
superForm(form, {
dataType: 'json'
})
)
);
I get this error
Uncaught Error: onDestroy can only be used during component initialisation.
Repro https://www.sveltelab.dev/9tdm9ul193m3tz5
- Click the Add button to add a new item (thus a new form)
A PR for this would be very nice!
Okay, I will send a PR for this
The problem is bigger than I anticipated, it'll require an overhaul of the onDestroy/cleanup handling. It'll have to wait until later. For now, calling superForm within $derived is not possible.
Okay, it will be good to have dynamic forms in the future. I will try to find a workaround for now.
Out of curiosity, what is the proscribed workaround for this? Just not to use superforms for an array of forms? Seems common to have a list of things, then have to a button to delete them individually...etc. Are folks just making client side individual API posts here for now?
There's an example here
How to use Superforms with actions on a list of data.
Although, I prefer not using the formId and instead get the submitter and alter the submitted data based on its props.
I also only submit tainted rows as I only need to save the text fields that the user modified.
Sample code below
const {
....
} = superForm(data.fields_form, {
dataType: 'json',
resetForm: false,
onSubmit({ submitter, jsonData }) {
const action = submitter?.getAttribute('name') || 'update'
const action_value = submitter?.getAttribute('value') || ''
jsonData({
...$form,
action,
action_value,
fields: Object.fromEntries(
Object.values($form.fields)
.filter((f) =>
Object.keys($tainted?.fields ?? {}).includes(f.id.toString()),
)
.map((f) => [ f.id, f ]),
),
})
},
})
Terribly embarrassed to say I missed that entire examples page. You made my day. TY!
Am I correct in assuming that this means that in Svelte 5 pre-filled forms will never update after submitting as the invalidated load function reruns but the form wont update unless wrapped in $derived, which isn't possible either?
So the only way then to use pre-filled forms in Svelte 5 seems to be to use
invalidateAll: false,
resetForm: false,
As long as you don't call superForm in $derived, it should work fine. A workaround for the array example is to call superForm for each data in a component instead, sending the SuperValidated form data as a prop:
{#each data.my_forms as form}
<ConditionForm {form} />
{/each}
See the componentization guide for more info.