diff --git a/playground/src/routes/paramOnNavigateBug/+page.svelte b/playground/src/routes/paramOnNavigateBug/+page.svelte
new file mode 100644
index 0000000..1c00224
--- /dev/null
+++ b/playground/src/routes/paramOnNavigateBug/+page.svelte
@@ -0,0 +1,20 @@
+
+
+
diff --git a/src/lib/sveltekit-search-params.ts b/src/lib/sveltekit-search-params.ts
index e3e7bf1..0945345 100644
--- a/src/lib/sveltekit-search-params.ts
+++ b/src/lib/sveltekit-search-params.ts
@@ -2,7 +2,7 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { browser, building } from '$app/environment';
import { goto } from '$app/navigation';
-import { page as page_store } from '$app/stores';
+import { navigating, page as page_store } from '$app/stores';
import type { Page } from '@sveltejs/kit';
import {
derived,
@@ -11,6 +11,8 @@ import {
type Updater,
type Writable,
type Readable,
+ type Subscriber,
+ type Unsubscriber,
readable,
} from 'svelte/store';
import {
@@ -326,8 +328,23 @@ export function queryParam(
const override = writable(null);
let firstTime = true;
let currentValue: T | null;
+
+ let isNavigating = false;
+
function _set(value: T | null, changeImmediately?: boolean) {
if (!browser) return;
+
+ // Wait for previous navigation to be finished before updating again
+ if (isNavigating) {
+ const unsubscribe = navigating.subscribe((nav) => {
+ if (nav?.type !== 'goto') {
+ _set(value, changeImmediately);
+ unsubscribe();
+ }
+ });
+ return;
+ }
+
firstTime = false;
const hash = window.location.hash;
const toBatch = (query: URLSearchParams) => {
@@ -376,10 +393,10 @@ export function queryParam(
});
}
- const { subscribe } = derived<[typeof page, typeof override], T | null>(
+ const store = derived<[typeof page, typeof override], T | null>(
[page, override],
([$page, $override], set) => {
- if ($override) {
+ if ($override != undefined) {
if (isComplexEqual(currentValue, $override, equalityFn)) {
return;
}
@@ -409,10 +426,29 @@ export function queryParam(
set(newValue) {
_set(newValue);
},
- subscribe,
update: (updater: Updater) => {
const newValue = updater(currentValue);
_set(newValue);
},
+ subscribe(
+ run: Subscriber,
+ invalidate?: (value?: T | null) => void,
+ ): Unsubscriber {
+ // Subscribe to the derived store
+ const storeUnsubscribe = store.subscribe(run, invalidate);
+ // Subscribe to isNavigating
+ let unsubscribeNavigating: () => void;
+ if (browser) {
+ unsubscribeNavigating = navigating.subscribe((nav) => {
+ isNavigating = nav?.type === 'goto';
+ });
+ }
+ return () => {
+ storeUnsubscribe();
+ if (unsubscribeNavigating) {
+ unsubscribeNavigating();
+ }
+ };
+ },
};
}
diff --git a/tests/index.test.ts b/tests/index.test.ts
index 6cd6bd4..6dcdf3b 100644
--- a/tests/index.test.ts
+++ b/tests/index.test.ts
@@ -133,6 +133,26 @@ test.describe('queryParam', () => {
expect(url.hash).toBe('#test-hash');
});
+ test('changing multiple parameters due to subscribe updates params accordingly', async ({
+ page,
+ }) => {
+ await page.goto('/paramOnNavigateBug');
+ const btn = page.getByTestId('update-params');
+ await btn.click();
+
+ // expect(url.searchParams.get('param1')).toBe('');
+
+ await page.waitForURL(
+ (url) => {
+ return (
+ url.searchParams.get('param1') === 'updated param1' &&
+ url.searchParams.get('param2') === 'updated param2'
+ );
+ },
+ { timeout: 1000 },
+ );
+ });
+
test("changing two parameters in the same function doesn't negate", async ({
page,
}) => {