Implementing a loading spinner in sveltekit that is triggered during an action
Asked Answered
F

3

6

I have a simple form having email, password and confirmPassword. I use action to handle this. I want to implement a spinner that will be triggered for the following actions

  1. Checking if user is currently existing in the db
  2. If no, then proceed for registration

I am using pocketbase

Following is my action.

import { superValidate } from 'sveltekit-superforms/server';
import { redirect } from '@sveltejs/kit';
import { fail } from '@sveltejs/kit';

import { loginSchema } from '$lib/schema/zodschema';
import { ClientResponseError } from 'pocketbase';

export const load = async () => {
    const form = await superValidate(loginSchema);
    return { form };
};

export const actions = {
    default: async ({ locals, request }) => {
        const form = await superValidate(request, loginSchema);


        try {

            const { email } = form.data
            const records = await locals.pb.collection('test').getFullList();
            const userRecords = records.filter(value => value.email === form.data.email);

            if (userRecords.length > 0) {

                const existingUser = userRecords[0]

                if (existingUser && existingUser.verified) {
                    return {

                        accountCreated: false,
                        message: 'The user records exists. Proceed to login instead',
                        isVerified: true,

                    }
                } else {


                    return {

                        accountCreated: false,
                        message: 'The user record exists. You have to verify to access',
                        isVerified: false,


                    }
                }
            } else {
                await locals.pb.collection('test').create(form.data);



                return {

                    accountCreated: true,
                    message: 'The user record is successfully created',
                    isVerified: false,
                }
            }



        } catch (error) {
            // Handle the error

            if (error instanceof ClientResponseError) {
                return {
                    error: error.message,
                    isLoading: false
                }
            }
        }
    }
};

In the above, I could set a boolean like

let isLoading = true

Then set it to false at different stages. But the problem is how to access the isLoading status in the client (both initial and updated state).

I tried stores only to find out later that stores cannot be used to share the state between the client and server.

Is there an alternative approach to achieve this?

Thanks

Fruiter answered 29/6, 2023 at 11:51 Comment(0)
M
20

It is not entirely clear to me, but it seems that you are trying to use Sveltekit form actions. Also, it is not clear to me why the loader needs to change during the server load.

What I would recommend is that you use a loading boolean in the client when the request starts and ends using progressive enhancement:

<script>
    import { enhance } from '$app/forms';

    /** @type {import('./$types').PageData} */
    export let data;

    let formLoading = false;
</script>

...
{#if formLoading}
    Loading...
{/if}
...
<form action="?/..." method="post" use:enhance={() => {
    formLoading = true;
    return async ({ update }) => {
        formLoading = false;
        update();
    };
}}>
    <button>SUBMIT</button>
</form>

Relative documentation: https://kit.svelte.dev/docs/form-actions#progressive-enhancement

Mislike answered 6/7, 2023 at 13:33 Comment(1)
It worked mate. This never crossed my mind. Thanks for the commentFruiter
C
0

Have you considered using the {#await} block?
What you can do is when you fetch the database it triggers the await block and when it's done, you can decide from there if you want to continue login or send to the registration page.

Refer to: https://svelte.dev/tutorial/await-blocks

So it can looks something like:

<script>
  let data;
  async function formSubmit() {
    data = await fetchData();

    ...
  }
</script>

{#await data}
  <Spinner />
{:then receivedData}
  <!-- Decide to send to registration or not -->
  <!-- you can either use the recievedData or just omit it -->
{:catch}
 <!-- Handle error -->
{/await}
Caulescent answered 29/6, 2023 at 17:57 Comment(2)
Apparently OP uses Sveltekit progressive enhancement on form actions so your recommendation although correct is not relevant.Mislike
Thanks for the response. However, note that I am using form action for handling the data. I don't think you can return a promise in the form action that you can use in the client in the await. But what @Mislike has suggested indeed has worked.Fruiter
P
0

I had to reorder the first answer like this:

  const formSubmit: SubmitFunction = ({ form, data, action, cancel }) => {
    formLoading = true;
    return async ({ update }) => {
      await update(); // Wait for this to complete
      formLoading = false;
    };
  };
Pianist answered 7/8, 2023 at 14:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.