Skip to content

Commit 9789e9f

Browse files
committed
The timers didn't reset after navigation in certain cases.
1 parent 5a21740 commit 9789e9f

File tree

12 files changed

+317
-22
lines changed

12 files changed

+317
-22
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ Headlines: Added, Changed, Deprecated, Removed, Fixed, Security
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [Unreleased]
9+
10+
### Fixed
11+
12+
- The timers didn't reset after navigation in certain cases.
13+
814
## [1.13.1] - 2023-12-22
915

1016
### Fixed

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@
9393
"@sveltejs/kit": "^1.30.3",
9494
"@sveltejs/package": "^2.2.4",
9595
"@types/throttle-debounce": "^5.0.2",
96+
"@types/uuid": "^9.0.7",
9697
"@typescript-eslint/eslint-plugin": "^5.62.0",
9798
"@typescript-eslint/parser": "^5.62.0",
9899
"devalue": "^4.3.2",
@@ -112,6 +113,7 @@
112113
"throttle-debounce": "^5.0.0",
113114
"tslib": "^2.6.2",
114115
"typescript": "^5.3.3",
116+
"uuid": "^9.0.1",
115117
"vite": "^4.5.1",
116118
"vitest": "^0.33.0",
117119
"zod": "^3.22.4"

pnpm-lock.yaml

Lines changed: 15 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/lib/client/formEnhance.ts

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { enhance, applyAction } from '$app/forms';
22
import { invalidateAll } from '$app/navigation';
3-
import { page } from '$app/stores';
3+
import { navigating, page } from '$app/stores';
44
import type { ActionResult } from '@sveltejs/kit';
55
import { get, type Readable, type Writable } from 'svelte/store';
66
import { browser } from '$app/environment';
@@ -548,19 +548,26 @@ export function formEnhance<T extends AnyZodObject, M>(
548548
// Also fixing an edge case when timers weren't resetted when redirecting to the same route.
549549
if (cancelled || result.type != 'redirect') {
550550
htmlForm.completed(cancelled);
551-
} else if (
552-
result.type == 'redirect' &&
553-
new URL(
554-
result.location,
555-
/^https?:\/\//.test(result.location)
556-
? undefined
557-
: document.location.origin
558-
).pathname == document.location.pathname
559-
) {
560-
// Checks if beforeNavigate have been called in client/form.ts.
561-
setTimeout(() => {
562-
htmlForm.completed(true, true);
563-
}, 0);
551+
} else if (result.type == 'redirect') {
552+
if (
553+
new URL(
554+
result.location,
555+
/^https?:\/\//.test(result.location)
556+
? undefined
557+
: document.location.origin
558+
).pathname == document.location.pathname
559+
) {
560+
// Checks if beforeNavigate have been called in client/form.ts.
561+
setTimeout(() => {
562+
htmlForm.completed(true, true);
563+
}, 0);
564+
} else {
565+
const unsub = navigating.subscribe(($nav) => {
566+
if ($nav) return;
567+
unsub();
568+
htmlForm.completed(cancelled);
569+
});
570+
}
564571
}
565572
}
566573

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<script>
2+
import './styles.css';
3+
</script>
4+
5+
<div class="app">
6+
<main>
7+
<slot />
8+
</main>
9+
</div>
10+
11+
<style>
12+
.app {
13+
display: flex;
14+
flex-direction: column;
15+
min-height: 100vh;
16+
}
17+
18+
main {
19+
flex: 1;
20+
display: flex;
21+
flex-direction: column;
22+
padding: 1rem;
23+
width: 100%;
24+
max-width: 64rem;
25+
margin: 0 auto;
26+
box-sizing: border-box;
27+
}
28+
</style>
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<script>
2+
import { v4 } from 'uuid';
3+
</script>
4+
5+
<svelte:head>
6+
<title>Home</title>
7+
<meta name="description" content="Svelte demo app" />
8+
</svelte:head>
9+
10+
<section>
11+
<h1>Superforms debug app</h1>
12+
<p>
13+
Description: the submitting store will be stuck as true forever in
14+
certaint cases
15+
</p>
16+
<p>Repro steps:</p>
17+
<ol>
18+
<li>Load this page "fresh" in a browser session</li>
19+
<li>
20+
<a href={`/tests/redirect-submitting/${v4()}`}>Open form page</a> (client
21+
side navigation)
22+
</li>
23+
<li>Submit form</li>
24+
<li>
25+
The submit will return a 303 to a different url with the same form.
26+
This form is "stuck" with $submtting = true forever
27+
</li>
28+
</ol>
29+
<p>
30+
The issue does not occur if you open the form page directly, omitting the
31+
client side navigation
32+
</p>
33+
</section>
34+
35+
<style>
36+
section {
37+
display: flex;
38+
flex-direction: column;
39+
justify-content: center;
40+
align-items: center;
41+
flex: 0.6;
42+
}
43+
44+
h1 {
45+
width: 100%;
46+
}
47+
</style>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// since there's no dynamic data here, we can prerender
2+
// it so that it gets served as a static asset in production
3+
export const prerender = true;
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { fail, redirect } from '@sveltejs/kit';
2+
import { superValidate } from '$lib/server';
3+
import { z } from 'zod';
4+
import { v4 } from 'uuid';
5+
6+
const sleep = (ms: number) =>
7+
new Promise((resolve) => setTimeout(resolve, ms));
8+
9+
const schema = z.object({
10+
name: z.string().default('Hello world!')
11+
});
12+
13+
export const actions = {
14+
default: async ({ request }) => {
15+
await sleep(1000);
16+
const form = await superValidate(request, schema);
17+
console.log('POST', form);
18+
19+
// Convenient validation check:
20+
if (!form.valid) {
21+
// Again, return { form } and things will just work.
22+
return fail(400, { form });
23+
}
24+
25+
// TODO: Do something with the validated form.data
26+
27+
// Yep, return { form } here too
28+
// return { form }
29+
throw redirect(303, `/tests/redirect-submitting/${v4()}`);
30+
}
31+
};
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<script lang="ts">
2+
import type { PageData } from './$types';
3+
import { superForm } from '$lib/client';
4+
5+
export let data: PageData;
6+
7+
// Client API:
8+
const { enhance, form, submitting } = superForm(data.form);
9+
10+
$: console.log('submitting', $submitting);
11+
</script>
12+
13+
<a href="/tests/redirect-submitting">Back</a>
14+
<form use:enhance method="POST">
15+
<label for="name">Name</label>
16+
<input type="text" name="name" bind:value={$form.name} />
17+
18+
<div><button disabled={$submitting}>Submit</button></div>
19+
</form>
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<svelte:head>
2+
<title>About</title>
3+
<meta name="description" content="About this app" />
4+
</svelte:head>
5+
6+
<div class="text-column">
7+
<h1>About this app</h1>
8+
9+
<p>
10+
This is a <a href="https://kit.svelte.dev">SvelteKit</a> app. You can make your own by typing the
11+
following into your command line and following the prompts:
12+
</p>
13+
14+
<pre>npm create svelte@latest</pre>
15+
16+
<p>
17+
The page you're looking at is purely static HTML, with no client-side interactivity needed.
18+
Because of that, we don't need to load any JavaScript. Try viewing the page's source, or opening
19+
the devtools network panel and reloading.
20+
</p>
21+
22+
<p>
23+
The <a href="/sverdle">Sverdle</a> page illustrates SvelteKit's data loading and form handling. Try
24+
using it with JavaScript disabled!
25+
</p>
26+
</div>

0 commit comments

Comments
 (0)