kbrgl / svelte-french-toast

šŸžšŸ„‚ Buttery smooth toast notifications for Svelte
https://svelte-french-toast.vercel.app/
MIT License
809 stars 28 forks source link

Using toast.promise with use:enhance #59

Closed Maratzz closed 3 months ago

Maratzz commented 8 months ago

Hi! Forgive me if it seems like a basic quesiton, I'm still learning Svelte(kit).

I have a Form component with use:enhance attached, sending data to the +page.server.js with POST and returning new data. I wanted to somehow use toast.promise before and after the form submission, as per the svelte docs , with the form property as promise but I'm not quite sure how and where to implement it. Could you give me some pointers?

+page.server.js looks like this

import { fail } from '@sveltejs/kit'

export const actions = {
  default: async ({ request }) => {
    const form = await request.formData()
    const newGame = form.get('new-game')
    const newPlatform = form.get('new-platform')

    if (!newGame) {
      return fail(400, { newGame, missing: true })
    }
    return { success: true, newGame, newPlatform }
  }
}

+page.svelte

<script>
  import Form from '$lib/components/Form.svelte'
  import toast, { Toaster } from 'svelte-french-toast'
  export let data
  export let form
</script>

<Form />

{#if form?.success}
  <p>Added {form.newGame} on {form.newPlatform}</p>
{/if}

Form.svelte

<script>
  import { enhance } from '$app/forms'
  export let categories
</script>

<form method='POST' use:enhance>
  <input type='text' name='new-game'>
  <input type='text' name='new-platform'>
  <button type='submit'>Create</button>
</form>
babakfp commented 7 months ago

Hey

So, do you want to show a toast, when the user logs in?

Code form:

<script>
    import toast from "svelte-french-toast"
</script>

<form
    method="POST"
    use:enhance={() => {
        return async ({ result, update }) => {
            toast.success("Successfully logged in!", {
                position: "bottom-right",
            })
        };
    }}
/>

in your layout file:

<script>
    import { Toaster } from "svelte-french-toast"
</script>

<Toaster />

This may not be a great place to ask for help. Try instead:

cassianodaniel commented 6 months ago

@babakfp It seems the loading state in the toast.promise callbacks are not being triggered when using use:enhance promise structure

import { applyAction, enhance } from '$app/forms';
<form
    method="POST"
    action="?/example"
    use:enhance={() => {
        return async ({ result }) => {
              toast.promise(applyAction(result), {
                  loading: 'Saving...',
                  success: 'Settings saved!',
                  error: 'Could not save.'
              });
        };
    }}
>
stefanosandes commented 3 months ago

@babakfp @cassianodaniel The way you ate doing it is starting toast in the page data invalidation, not on form submission. The code inside return async ({ result, update }) => { is runing after the action execution. It will create an initial delay. What toast is really waiting is the page data loading, not the form submission.

<form
    method="POST"
    use:enhance={() => {
                // START OF FORM SUBMISSION
        return async ({ result, update }) => {
            // SUBMISSION HAS DONE
                        // BEFORE START UPDATING PAGE DATA
                       await update()
                        // PAGE DATA UPDATED
        };
    }}
/>
stefanosandes commented 3 months ago

So, the best way to do this is something like:

<form
    method="POST"
    use:enhance={() => {
        // START OF FORM SUBMISSION
        const toastId = toast.loading('Doing something..') 
        return async ({ result, update }) => {
            // SUBMISSION HAS DONE
            // BEFORE START UPDATING PAGE DATA
           await update()
            // PAGE DATA UPDATED
           toast.success('Done!', { id: toastId });
        };
    }}
/>
Maratzz commented 3 months ago

Apologies for the late reply, I ended up doing a new Promise similar to what @cassianodaniel suggested.

<form method="POST" action="?/insert" use:enhance={() => {
  let toastResolve, toastReject
  let toastPromise = new Promise(( resolve, reject ) => {
    toastResolve = resolve
    toastReject = reject
  })
  toast.promise(toastPromise, {
    loading: "Saving...",
    success: (e) => `${e}`,
    error: (e) => `${e.message}`,
  })

  return ({ result, update }) => {
    if ( result.data === "no game found" ) {
      toastReject(new Error( "no game found" ))
    } else {
      toastResolve("OK !")
      update()
    }
  }
}}>