1

I've got an Artist page in SvelteKit. Its route looks like the following:

routes
    artists
        [slug]
            +page.server.js
            +page.svelte
        new
            +page.server.js
            +page.svelte
...

I've abstracted the form itself into a component called ArtistForm.svelte, for the purposes of this issue I'll show just one field:

<script>
    export let formData;
    export let mode = "new";

</script>

<form method="POST" use:enhance>
    {#if (mode !== "new") }
        <input type="hidden" name="id" value={ formData.id } />
    {/if}

    <!-- Row 1: name, type -->
    <div class="flex flex-row">

        <div class="basis-1/2 form-control w-full">
            <label class="label">
                <span class="label-text">Name <span class="required-field">*</span></span>
            </label>
            <input
                    name="name"
                    id="name"
                    type="text"
                    value={ formData?.name || "" }
                    class="input input-bordered w-full max-w-xs"/>
            {#if formData?.errors?.name}
            <label for="name" class="label">
                    <span class="label-text-alt text-error">{ formData?.errors.name[0]}</span>
            </label>
            {/if}
        </div>
   </div>
   <div class="flex flex-row">
        <button type="submit" class="btn btn-primary">{ mode == "new" ? "Save" : "Update" }</button>
    </div>

</form>

So in artists\[slug]\+page.svelte I've simply got:

<script>
    import ArtistForm from "../../../components/forms/ArtistForm.svelte";

    /* data returned from load function in +page.server.js */
    export let data;

    /* data returned from actions in +page.server.js */
    export let form;

</script>

<ArtistForm formData={data} mode="edit" />

and in artists\new\+page.svelte I've got:

<script>
    import ArtistForm from "../../../components/forms/ArtistForm.svelte";

    /* data returned from actions function in +page.server.js */
    export let form;

</script>

<ArtistForm formData={form} mode="new" />

So far so good. The issue comes when validating the data. So the action for new looks something like:

export const actions = {
    default: async ({ request }) => {

        const data = Object.fromEntries(await request.formData());
        const artist = artistDTO(data);

        // if errors returned from building the DTO (validation errors) then return the object.
        if (artist?.errors && !emptyObject(artist.errors)) {
            return artist;
        }

        const response = await createArtist(artist);

        return {
            ...artist,
            "errors": response.errors,
        }
    }
};

If there are any validation errors it will return the fields plus the errors in an object.

For edit mode ([slug]) the action looks similar to the previous one.

When an error occurs on new, then the object returned from the action is assigned to formData so the entered fields are populated again plus there's gonna be an errors object from which errors will be displayed.

With the new form there are no issues.

But with the edit form ([slug]), I've got issues. When the page first loads then the object returned from the load method is assigned to formData so the form is populated with that data, but when the form is submitted, then if any errors are encountered and returned from the action, that object will be assigned to form and not to data, and form is not being passed into ArtistForm, but even if I decided to pass it, I'd need to know when to pull data from data and from form.

How can I achieve that? Not sure if the question is not clear, please let me know if more details are needed.

1 Answer 1

1

You could spread both form and data into the form component, something along the lines of:

<ArtistForm formData={{...data, ...form}} mode="edit" />
1
  • Good thinking, i'll try that. What's the usual way to do it? I mean, how people usually do a edit page? they all have to face these same issues with load and data right?
    – MrCujo
    Commented Mar 16, 2023 at 0:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.