Search code examples
sveltesveltekit

How can I submit multi-page form in SvelteKit with Form Actions?


Normally, I store all the values of a form and send POST request to the server if it is a multipage form. But what if I have a form like this in my +page.svelte:

<script lang="ts">
    import {enhance} from "$app/forms";

    let page: number = 1;
    const nextPage = () => {
        page++;
    }

    const prevPage = () => {
        page--;
    }

</script>
<form method="POST" use:enhance>
    {#if page === 1}
        <label for="name">Name</label>
        <input type="text" id="name" name="name" value="John Doe">
    {:else if page === 2}
        <label for="email">Email</label>
        <input type="email" id="email" name="email">
    {:else if page === 3}
        <label for="password">Password</label>
        <input type="password" id="password" name="password">
        <button type="submit">Register</button>
    {:else}
        <p>Thank you for registering!</p>
    {/if}
    <button type="button" on:click={prevPage} disabled={page === 1}>Previous</button>
    <button type="button" on:click={nextPage} disabled={page === 4}>Next</button>
</form>

and I want to send these Form data to server, inside of +page.server.ts so that the server logs all the value (I can work with those value later like authentication or something)

+page.server.ts File:

export const actions = {
    default: async ({request}: any) => {
        const formData = await request.formData();

        const name = formData.get('name');
        const email = formData.get('email');
        const password = formData.get('password');

        console.log(name, email, password)
    }
}

Upon submitting, server is printing null null ezpass

given that name = John, email = [email protected], password = ezpass)

Is there any way of sending all the information to the +page.server.ts like this? Or I should do the other way, which is storing everything and make a POST request in the +page.svelte (I don't want to do that, I want to use form actions).


Solution

  • Instead of using #if, which removes the element completely, just hide the pages that are not the current one.

    E.g.

    <div class="page" class:show={page === 1}>
        <label for="name">Name</label>
        <input type="text" id="name" name="name" value="John Doe">
    </div>
    <div class="page" class:show={page === 2}>
        <label for="email">Email</label>
        <input type="email" id="email" name="email">
    <div>
    ...
    
    <style>
      .page { display: none; }
      .page.show { display: block; }
    </style>
    

    An alternative would be to mirror all values in <input type="hidden"> elements that always exist, though then you need to bind everything and you always have to maintain values in two places.

    Likewise it is also possible to add values to an action's formData in the enhance action's submit handler.