Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deprecate events passed to enhance? #466

Open
gbouteiller opened this issue Aug 13, 2024 · 6 comments
Open

Deprecate events passed to enhance? #466

gbouteiller opened this issue Aug 13, 2024 · 6 comments
Milestone

Comments

@gbouteiller
Copy link

  • [✓] Before posting an issue, read the FAQ and search the previous issues.

Description
When events are added to use:enhance, if the form element is created and destroyed multiple times (for example, the form is in a sheet or dialog or, even simpler, in an if like in the MRE below), the events are pushed multiple times to formEvents but never destroyed.

MRE
In that example, if you toggle the form multiple times, you can see that onUpdated is called multiple times

Possible solution
Instead of returning kitEnhance here :

return kitEnhance(FormElement, async (submitParams) => {

it could be something like this :

const enhance = kitEnhance("...");
return {
  destroy: () => {
    // same as in onDestroy()
    for (const events of Object.values(formEvents)) {
      events.length = 0;
    }
    // call native enhance destroy
    enhance.destroy();
  }
}

What are your thoughts?
By the way, thank you again for this awesome library.

@gbouteiller gbouteiller added the bug Something isn't working label Aug 13, 2024
@ciscoheat
Copy link
Owner

Thank you, will take a look and hopefully it will be included in the next release. Glad you like Superforms. :)

@ciscoheat ciscoheat added next Will be implemented in the next release done Implemented enhancements labels Aug 13, 2024
@ciscoheat
Copy link
Owner

I've added a fix for the next release. Do you have any good reason not to put the event(s) directly in the options when calling superForm? I'm considering deprecating this "add events in enhance" feature, as I have never found a really good use case for it.

@gbouteiller
Copy link
Author

I'm creating an app with crud functionalities.
I have a generic page as a component for each collection where generic events are passed to the enhance action of a superform passed as a prop and instantiated in the specific page (see below).

components/ui/items-page.svelte (simplified version)

<script lang="ts" generics="Item extends {id: string}, Upsert extends Record<string, any>">
  let {isAdmin, items, sfDelete, sfUpsert, UpsertFields}: ItemsPageProps<Item, Upsert> = $props()
  let {delayed: delayedDelete, enhance: enhanceDelete, form: formDelete, message: messageDelete, submitting: submittingDelete} = sfDelete
  let {delayed: delayedUpsert, enhance: enhanceUpsert, message: messageUpsert, reset, submitting: submittingUpsert} = sfUpsert

  const onUpdated = () => toast.success("...")
</script>

<div>
  {#if isAdmin}
    <div>{@render UpsertSheet()}</div>
  {/if}
  ...
</div>

{#snippet UpsertSheet()}
  <Sheet.Root>
    <Sheet.Trigger>Create</Sheet.Trigger>
    <Sheet.Content>
      <form method="post" action="?/upsert" use:enhanceUpsert={{onUpdated}}>
        {@render UpsertFields()}
        <Form.Button>Submit</Form.Button>
      </form>
    </Sheet.Content>
  </Sheet.Root>
{/snippet}

For each collection like projects, I create a page where I instantiate the superforms for upsert and delete. The instantiation is done here to pass the upsert superform to the FormSnap components and to bind to field values

projects/+page.svelte (simplified version)

<script lang="ts">
  let {data}: {data: PageData} = $props()
  let {isAdmin, items} = $derived(data)

  let sfDelete = superForm(data.svDelete, {validators: zodClient(deleteSchema)})
  let sfUpsert = superForm(data.svUpsert, {validators: zodClient(projectUpsertSchema)})
  let {form} = sfUpsert
</script>

<ItemsPage {isAdmin} {items} {sfDelete} {sfUpsert}>
  {#snippet UpsertFields()}
    <input type="hidden" name="id" value={$form.id} />
    <Form.Field form={sfUpsert} name="name">
      <Form.Control let:attrs>
        <Form.Label>Nom</Form.Label>
        <Input {...attrs} bind:value={$form.name} />
      </Form.Control>
      <Form.FieldErrors />
    </Form.Field>
  {/snippet}
</CollectionItemsPage>

I have tried to instantiate the superform directly in the generic component and pass its $form store to the specific page via a snippet param but I lose reactivity.

@ciscoheat
Copy link
Owner

I'm not sure I understand still, since onUpdated looks like a simple toast notification (maybe you've simplified it), what prevents you from adding it directly?

let sfUpsert = superForm(data.svUpsert, {
  validators: zodClient(projectUpsertSchema),
  onUpdated: () => toast.success("...")
})

@gbouteiller
Copy link
Author

As you said , I simplified it 🙂. In fact, I use it for multiple interactions on the generic page (closing the sheet, updating some data, etc...). But even if it was a simple toast, I want the toast to be on the generic page as I don't want, if I have 10 collections, to define the same behavior 10 times (hence the generic crud component 🙂).

@ciscoheat
Copy link
Owner

Right, but if you use it in multiple locations, it will append the events to the others as well, and there are internal state that may cause problems too. That's why I'm not sure it's the best to keep. It's was a very early feature.

@ciscoheat ciscoheat removed bug Something isn't working next Will be implemented in the next release done Implemented enhancements labels Aug 15, 2024
@ciscoheat ciscoheat changed the title Events passed to enhance are not correctly destroyed Deprecate events passed to enhance? Aug 15, 2024
@ciscoheat ciscoheat added this to the v3 milestone Aug 20, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants