sveltekit-superforms icon indicating copy to clipboard operation
sveltekit-superforms copied to clipboard

See if any forms are submitting

Open liegeandlief opened this issue 2 years ago • 9 comments

Is your feature request related to a problem? Please describe.

As discussed in https://github.com/ciscoheat/sveltekit-superforms/issues/201 it would be helpful to know if any forms are currently submitting. For example it could be used to show a global loading indicator without having to add logic to every form instance.

Describe the solution you'd like

Something like:

<script>
import { anyFormsSubmitting } from 'sveltekit-superforms/client'
import GlobalLoadingIndicator from '$lib/components/GlobalLoadingIndicator.svelte'
</script>

<!-- where $anyFormsSubmitting is a boolean -->
{#if $anyFormsSubmitting}
    <GlobalLoadingIndicator />
{/if}

Describe alternatives you've considered

This could be managed by creating a derived store with the $submitting value for each form but this would create duplication and it would be easy to forget to include a particular form.

liegeandlief avatar Jun 29 '23 14:06 liegeandlief

This could possibly be combined with issuing a warning if there are multiple forms with the same id present on the same page.

ciscoheat avatar Jul 08 '23 23:07 ciscoheat

After testing it out, it's both a rather complicated and expensive operation (a dynamically derived store cannot be directly accessed), so I have to say no to this feature, sorry.

ciscoheat avatar Jul 09 '23 01:07 ciscoheat

Where does the complexity come from? Could it not be something as simple as this:

import { writable, derived } from 'svelte/store'

const submittingForms = writable<string[]>([])
export const areAnyFormsSubmitting = derived(submittingForms, ($submittingForms) => $submittingForms.length > 0)

export const addSubmittingForm = (id: string) => {
	submittingForms.update((ids) => [...ids, id])
}

export const removeSubmittingForm = (id: string) => {
	submittingForms.update((ids) => ids.filter((i) => i !== id))
}

addSubmittingForm would be called in the same place where submitting for an individual form is set to true. removeSubmittingForm would be called in the same place where submitting for an individual form is set to false and could also be manually called in the onDestroy of a component where the form is used.

liegeandlief avatar Jul 09 '23 09:07 liegeandlief

Identical id:s can exist on the same page, new forms can be added/returned in different places and needs to be tracked, the submitting stores needs to be checked with get in the derived store, making it expensive, for example.

ciscoheat avatar Jul 09 '23 10:07 ciscoheat

I didn't quite understand your previous comment so I created a proof-of-concept to illustrate my suggestion - https://github.com/ciscoheat/sveltekit-superforms/pull/226

liegeandlief avatar Jul 10 '23 06:07 liegeandlief

The thing is that there is already a $submitting store for the forms, using that would be the optimal solution, but it's quite complicated for said reasons. Your POC is kind of a double-work in that sense, it works but is not really related to superforms, it's basically its own action, so maybe it's better to use it that way. It's very hard to draw the line somewhere, but I'm reopening this anyway.

ciscoheat avatar Jul 10 '23 10:07 ciscoheat

I did this in my own way by using a derived store and just saved "submitting" to it.

$: $projectStore.name.submitting = $submitting;
export const saving = derived(
	[itemStore, projectStore],
	([$itemStore, $projectStore]) => $itemStore.submitting || $projectStore.name.submitting
);

saturnonearth avatar Jul 26 '23 00:07 saturnonearth

Not sure I completely understand your solution @saturnonearth but it looks like it requires adding the submitting state of each form to the derived store, which is what I'm trying to avoid.

I'd like the library to inform me if any form is submitting, in much the same way as SvelteKit informs me if a navigation is occurring via the navigating store provided by $app/stores.

liegeandlief avatar Jul 26 '23 00:07 liegeandlief

Hi, I also needed this and came up with the following helper function:

import { navigating } from '$app/stores';
import { derived, writable } from 'svelte/store';
import { superForm } from 'sveltekit-superforms/client';

const submittingCount = writable(0);

export const loading = derived(
  [navigating, submittingCount],
  ([$navigating, $submittingCount]) => $navigating !== null || $submittingCount > 0,
);

export const superFormWithLoading: typeof superForm = (form, options) => {
  const _form = superForm(form, options);

  let isTracked = false;

  _form.submitting.subscribe(($submitting) => {
    if (!isTracked) {
      isTracked = true;
    } else if ($submitting) {
      submittingCount.update(($c) => $c + 1);
    } else {
      submittingCount.update(($c) => $c - 1);
    }
  });

  return _form;
};

isTracked is used for skipping the first subscriber update which is not a real change but the initial value of false. Otherwise the count would be initiated with -1.

fehnomenal avatar Nov 10 '23 09:11 fehnomenal