summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Matthew Phillips <matthew@skypack.dev> 2023-11-10 11:23:31 -0500
committerGravatar GitHub <noreply@github.com> 2023-11-10 11:23:31 -0500
commitf105b1002bd4f355955c5d5366bdd453cfd2281f (patch)
treebad2094ba0d03fbce43194cc6e36bfcba69e021a
parent1bc3319686808292322ea3f7e5df3b4a37357111 (diff)
downloadastro-f105b1002bd4f355955c5d5366bdd453cfd2281f.tar.gz
astro-f105b1002bd4f355955c5d5366bdd453cfd2281f.tar.zst
astro-f105b1002bd4f355955c5d5366bdd453cfd2281f.zip
Allow same-page navigations on form posts (#9055)
* Allow same-page navigations on form posts * Add another comment
-rw-r--r--packages/astro/components/ViewTransitions.astro3
-rw-r--r--packages/astro/e2e/fixtures/view-transitions/src/pages/form-two.astro17
-rw-r--r--packages/astro/e2e/view-transitions.test.js22
-rw-r--r--packages/astro/src/transitions/router.ts3
4 files changed, 43 insertions, 2 deletions
diff --git a/packages/astro/components/ViewTransitions.astro b/packages/astro/components/ViewTransitions.astro
index 908b35595..2e8b93c2f 100644
--- a/packages/astro/components/ViewTransitions.astro
+++ b/packages/astro/components/ViewTransitions.astro
@@ -89,7 +89,8 @@ const { fallback = 'animate', handleForms } = Astro.props;
const form = el as HTMLFormElement;
const formData = new FormData(form);
- let action = form.action;
+ // Use the form action, if defined, otherwise fallback to current path.
+ let action = form.action ?? location.pathname;
const options: Options = {};
if (form.method === 'get') {
const params = new URLSearchParams(formData as any);
diff --git a/packages/astro/e2e/fixtures/view-transitions/src/pages/form-two.astro b/packages/astro/e2e/fixtures/view-transitions/src/pages/form-two.astro
new file mode 100644
index 000000000..01131ee84
--- /dev/null
+++ b/packages/astro/e2e/fixtures/view-transitions/src/pages/form-two.astro
@@ -0,0 +1,17 @@
+---
+import Layout from '../components/Layout.astro';
+
+if(Astro.request.method === 'POST') {
+ const formData = await Astro.request.formData();
+ const name = formData.get('name');
+ return Astro.redirect(`/form-response?name=${name}`);
+}
+---
+<Layout>
+ <h2>Contact Form</h2>
+ <h3>This form does not have an `action` defined</h3>
+ <form method="post">
+ <input type="hidden" name="name" value="Testing">
+ <input type="submit" value="Submit" id="submit">
+ </form>
+</Layout>
diff --git a/packages/astro/e2e/view-transitions.test.js b/packages/astro/e2e/view-transitions.test.js
index 41f10a3aa..ac0af3be2 100644
--- a/packages/astro/e2e/view-transitions.test.js
+++ b/packages/astro/e2e/view-transitions.test.js
@@ -982,4 +982,26 @@ test.describe('View Transitions', () => {
]);
expect(reqUrls).toContainEqual('/one');
});
+
+ test('form POST with no action handler', async ({ page, astro }) => {
+ const loads = [];
+ page.addListener('load', async (p) => {
+ loads.push(p);
+ });
+
+ await page.goto(astro.resolveUrl('/form-two'));
+
+ let locator = page.locator('h2');
+ await expect(locator, 'should have content').toHaveText('Contact Form');
+
+ // Submit the form
+ await page.click('#submit');
+ const span = page.locator('#contact-name');
+ await expect(span, 'should have content').toHaveText('Testing');
+
+ expect(
+ loads.length,
+ 'There should be only 1 page load. No additional loads for the form submission'
+ ).toEqual(1);
+ });
});
diff --git a/packages/astro/src/transitions/router.ts b/packages/astro/src/transitions/router.ts
index b5f198653..8c008e209 100644
--- a/packages/astro/src/transitions/router.ts
+++ b/packages/astro/src/transitions/router.ts
@@ -463,9 +463,10 @@ export function navigate(href: string, options?: Options) {
}
const toLocation = new URL(href, location.href);
// We do not have page transitions on navigations to the same page (intra-page navigation)
+ // *unless* they are form posts which have side-effects and so need to happen
// but we want to handle prevent reload on navigation to the same page
// Same page means same origin, path and query params (but maybe different hash)
- if (location.origin === toLocation.origin && samePage(toLocation)) {
+ if (location.origin === toLocation.origin && samePage(toLocation) && !options?.formData) {
moveToLocation(toLocation, options?.history === 'replace', true);
} else {
// different origin will be detected by fetch