paoloricciuti / sveltekit-search-params Goto Github PK
View Code? Open in Web Editor NEWThe easiest way to read and WRITE from query parameters in sveltekit.
Home Page: https://sveltekit-search-params.netlify.app
License: MIT License
The easiest way to read and WRITE from query parameters in sveltekit.
Home Page: https://sveltekit-search-params.netlify.app
License: MIT License
creating a store and immediately accessing it in the root layout while defining a parameter with a default value causes the initial value to be undefined.
In the reproduction, there is a parameter "foo" with default "bar". accessing /, the url is updated to include ?foo=bar but the initial value in +layout.svelte is undefined.
This is unexpected and causes an error if you want to access $params.foo
.
Possible solutions:
https://www.sveltelab.dev/49is8k7v2xv3ap3
No response
I've encountered a weird behavior where if im getting any data from the url params on the server, I can't update it at all on the page.
Once I remove the url.searchParams.get() methods, it starts working again, it's very odd..
here's a reproduction
https://stackblitz.com/edit/sveltejs-kit-template-default-zzzvcz
Reproduction here: #1 (comment)
When writing to a query param the store only updates once the navigation has finished, this can cause a non-instant change when using user input like a select. This feels janky and isn't good UX. This is especially noticable when load functions are doing work since navigation only resolves once the load function finishes.
I don't know if this is technically feasable within the library but my proposal is to optimistically update the store. So instead of just mutating the URL and letting the subscribe handle the updates you can optimistically set the store before the navigation even happens so the store is updated immediately.
Downside would be that the update would cause subscribers to get notified 2 times. (Unless you can detect the value was updated optimistically and only update if the optimistic value doesn't match the actual URL value).
If there is a default version of a parameter it can be nice to not have it show up in the URL.
If encode returns undefined delete the parameter from the url.
Thanks for this awesome library!
Simple issue - the default value of an array param when using the ssp.array()
helper is not typed correctly.
Currently we have
array: <T = any>(defaultValue?: T) => ({
encode: (value: T[]) => JSON.stringify(value),
decode: (value: string | null): T[] | null => {
if (value === null) return null;
try {
return JSON.parse(value);
} catch (e) {
return null;
}
},
defaultValue,
}),
The default value should be typed as T[]
and not T
.
No response
Provide an api to check validity of query keys and provide defaults if invalid.
For whatever reason some users try to modify our search params manually. We assume this mostly happens when a url not fully copied to the clipboard. Nonetheless you'll end up with a query that looks like ?sort=highes
for example; where the "t" is cutoff.
At the moment we are the default
parameter but that only adds a default value if the key is not present instead of checking if the value is valid it seems.
We are currently checking this in our onMount
like so; but it gets verbose when there are 15 keys to check for (search heavy data app).
onMount(() => {
if ($store.sort !== 'highest' ?? $store.sort !== 'recent') {
$store.sort = 'highest';
}
});
An api similar to the default
feature that would not only check for a missing key, but check for its validity and set a default value if invalid.
We just updated from "@sveltejs/kit": "^1.24.1"
to "@sveltejs/kit": "^2.5.0"
and started getting the warning:
Avoid using
history.pushState(...)
andhistory.replaceState(...)
as these will conflict with SvelteKit's router. Use thepushState
andreplaceState
imports from$app/navigation
instead.
This just happens every time we write to the query-params.
No response
With optional parameters it is currently possible to add them at different times, and their insertion order determines their position in the query string of the url.
http caching uses the full url , so https://example.com?a=1&b=2
is a different entry than https://example.com?b=2&a=1
In order to have a more stable url representation and improve cache hit rate, it would be great if the params can be sorted.
use native sort() by default, add an option for custom sort function (or false to disable)
After I open a page with this library configured I cannot navigate to any other page.
The URL does change but my app still shows the same page which is using sveltekit-search-params
Will setup a reproduction and add here.
No response
Hi,
I have 2 search parameters:
Imagine a user is on page 2 and then selects an ingredient. At this moment, I want to reset the page to "1" to start from the beginning. In fact, this reset may occur each time the filter is updated.
Here's how I achieve this:
const currentPage = queryParam('page', ssp.number(1))
const selectedIngredients = queryParam('ingredients', ssp.array([]), { showDefaults: false })
selectedIngredients.subscribe((value) => {
if (!value) {
return;
}
currentPage.set(1)
})
Unfortunately, the filters stop working with this logic. It becomes impossible to check/uncheck ingredients.
No response
Not sure if this is a bug, but let me explain.
When I create a new query param store with an empty array as the default value and showDefaults set to false, everything is fine on the first load. The query param is not added to the URL.
Adding an element to the array and the URL updates accordingly.
But now when I remove the object again or assign []
to the store, the query param is added to the URL with an empty array value.
@paoloricciuti Would love to hear you opinion on what the expected behavior should be. IMO the query param should disappear again after it has been reset to its default value.
Already have an idea that the issue comes from comparison by reference instead of comparison by value, but want to wait for your feedback first, before jumping into any code.
Cheers!
// creating the store, no query param in the URL
const params = queryParam('params', ssp.array([]), { showDefaults: false });
// adding element to store array, URL updates to ?params=["foo"]
$params = ['foo']
// resetting store to empty array, URL updates to ?params=[]
$params = []
No response
Given this code:
const booleanFilters = queryParam('bf', ssp.array<string>([]));
I get this typescript error when exactOptionalPropertyTypes
is true in my tsconfig
Argument of type '{ encode: (value: string[]) => string; decode: (value: string | null) => string[] | null; defaultValue: string[] | undefined; }' is not assignable to parameter of type 'EncodeAndDecodeOptions<string[]>' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties.
Types of property 'defaultValue' are incompatible.
Type 'string[] | undefined' is not assignable to type 'string[]'.
Type 'undefined' is not assignable to type 'string[]'.ts(2379)
import { ssp, queryParam } from 'sveltekit-search-params';
const booleanFilters = queryParam('bf', ssp.array<string>([]));
No response
it can be nasty to the browser history when we type and the url bar is updated on every keystroke.
could we offer an easy way (probably not default, but recommended) to debounce the updates?
I have this setting:
const store_qp = queryParameters({
withOne: ssp.boolean(true),
withTwo: ssp.boolean(false),
pushHistory: false,
})
First time I see the page, I see my queryParams getting updated, it's all good.
Then, I navigate (client side), and when at some point I go back to this page, defaults don't get applied.
When, I leave the page, my +page.svelte get destoyed well. So I'm not sure what's happening.
Thanks for your help
https://www.sveltelab.dev/?provider=github&owner=jycouet&repo=veltekit-search-params-default-value
No response
How do I get an empty query string off the URL?
Add with data then try to remove.
No response
Whenever I do a hard refresh, I get this error. Not sure what I am missing!
https://stackblitz.com/edit/sveltejs-kit-template-default-c78wrs?file=src%2Froutes%2F%2Bpage.svelte
00:48:40 [vite] Error when evaluating SSR module /src/routes/+page.svelte: failed to import "sveltekit-search-params"
|- Error [ERR_MODULE_NOT_FOUND]: Cannot find package '$app' imported from /home/projects/sveltejs-kit-template-default-c78wrs/node_modules/sveltekit-search-params/package/sveltekit-search-params.js
at (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:36:4170)
at packageResolve (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:114:9613)
at (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:114:11319)
at (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:114:12167)
at defaultResolve (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:114:12837)
at (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:248:2121)
at (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:248:2213)
at (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:248:7557)
at resolve (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:248:7997)
at (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:248:4394)
at getModuleJob (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:248:4673)
at (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:181:944)
at (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:181:989)
at (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:352:382940)
at (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:181:897)
Error [ERR_MODULE_NOT_FOUND]: Cannot find package '$app' imported from /home/projects/sveltejs-kit-template-default-c78wrs/node_modules/sveltekit-search-params/package/sveltekit-search-params.js
at (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:36:4170)
at packageResolve (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:114:9613)
at (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:114:11319)
at (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:114:12167)
at defaultResolve (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:114:12837)
at (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:248:2121)
at (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:248:2213)
at (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:248:7557)
at resolve (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:248:7997)
at (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:248:4394)
at getModuleJob (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:248:4673)
at (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:181:944)
at (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:181:989)
at (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:352:382940)
at (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:181:897) {
code: 'ERR_MODULE_NOT_FOUND'
}
client-manifest.js:28 SyntaxError: The requested module '/node_modules/.pnpm/[email protected]/node_modules/lz-string/libs/lz-string.js?v=2285ece9' does not provide an export named 'compressToEncodedURIComponent' (at sveltekit-search-params.js?v=2285ece9:7:10)
handleError @ client-manifest.js:28
using:
"@sveltejs/adapter-auto": "next",
"@sveltejs/kit": "1.0.0-next.561",
I would like to do some computations in a derived store based on values returned from queryParameters
but can't figure out how. I guess that it may currently not be possible based on how queryParameters
is exported? Currently it's exported as a function but the derived store expects a writable store
as an argument.
It would be great to have an exported writable store
that could be used as such:
export const derivedStore = derived([queryParameters, anotherStore], ([$queryParameters, $anotherStore]) => {
const { param1, param2, ... } = $queryParameters;
// ...
});
First off, I'll say that I haven't verified if this happens without the use of your plugin.
const search = queryParam('q', ssp.string(), {pushHistory: false})
...
<input type="search" name="search" placeholder="Search" bind:value={$search} />
Running this on Node 18, no calls to __data.json happen when typing in the input. But when I upgrade to Node 20, I see a request to __data.json on every keystroke.
It took me a looong time to figure out what the culprit was. I created a whole Stackblitz for you, only to find that the issue wasn't there because apparently it runs Node 16.
https://stackblitz.com/edit/sveltejs-kit-template-default-d1rzdh?file=README.md
No response
Svelte 5 is right around the corner and while stores are still supported i want to upgrade this library to take advantage of runes.
This however require some changes that are not back compatible so my plan is to continue supporting stores in sveltekit-search-params@^2
and upgrade to runes in sveltekit-search-params@^3
.
The new version however will likely face some api changes because of how runes behave.
queryParameters
The function queryParameters
will benefit a lot from runes: today this function return an unique store object with each query parameter as the key.
<script>
import { ssp, queryParameters } from "sveltekit-search-params";
const params = queryParameters({
search: ssp.string(),
});
</script>
<input bind:value={$params.search} />
with runes the syntax will not change that much but the updates should be much more fine grained which is good
<script>
import { ssp, queryParameters } from "sveltekit-search-params";
const params = queryParameters({
search: ssp.string(),
});
</script>
<input bind:value={params.search} />
queryParam
Here's where the change will be much more intensive so first thing first sorry if you are using this intensively...i'll try to see if i can create a migration CLI to help you with your upgrade.
Today queryParam
accept the key of the query parameter as input and returns a store with that param by itself. If the query parameter is a string the store will contain the string itself.
<script>
import { ssp, queryParam } from "sveltekit-search-params";
const search = queryParam("search");
</script>
<input bind:value={$search} />
This is not possible with runes so we have three options:
The simplest option would to return a ref
or a boxed
instead of the actual value. The downside is that you need to access it with .value
everywhere.
<script>
import { ssp, queryParam } from "sveltekit-search-params";
const search = queryParam("search");
</script>
<input bind:value={search.value} />
This is simple to refactor but once you need to access it with .value
everywhere is it really worth it over using queryParameters
with a short name and just access it like qp.search
everywhere?
Another option could be have the returned value be a function...you could access it by calling it and set it by calling it with a typesafe parameter.
<script>
import { ssp, queryParam } from "sveltekit-search-params";
const search = queryParam("search");
</script>
<input value={search()} oninput={(e)=>{search(e.target.value)}} />
this is nice to see but it can get complex with Typescript type narrowing and it get's pretty hairy with objects and arrays.
A somewhat nice option would be to make use of $derived.by
to destructure the return value of queryParam
. This would give us a simple value to use everywhere and we could even return an input
object to spread into your inputs that automatically set the oninput
property to mimic the bind
behaviour.
<script>
import { ssp, queryParam } from "sveltekit-search-params";
const [search, inputsearch, setsearch] = $derived.by(queryParam("search"));
</script>
<input {...inputsearch} />
The search is {search}
but this again become very hairy with object and arrays (especially if you want to bind a property of that object instead of the whole object).
I'm not really satisfied with any of the options for queryParam
and i wonder if we should just drop that api but i would love to have YOUR opinion and ideas on this.
As soon as a component that uses a parameters store unsubscribes from it, the connection to sveltekits page store is severed. This prevents updates from reaching other subscribers to the same store.
Possible Solutions:
StartStopNotifier or counting subscribers to know when it is safe to unsubscribe from page
https://www.sveltelab.dev/2z7v7xq7im6erv1
No response
i notice this when i building my pagination component, i use this code
const current_page = queryParam("page", ssp.number(1));\
and using this button to go to previous page
<button class="grid place-items-center bg-white border-gray-600 shadow-md" on:click={() => current_page.update((e) => { const new_val = Math.max((e ?? 1) - 1, 1); return new_val; })} > < </button>
the current_page state gets updated but the brower url doesn't.
Hi @paoloricciuti , the library is very useful, thanks.
I have a question with regards to replaceState
How do we achieve this
goto(`?tab=${tab}`, { replaceState: true });
with the query params library
Are you working on a Svelte 5 version?
Hi, I am excited to use your plugin as it does everything I need to maintain state using query params, thank you for developing it!
I noticed that when I update a queryParam, it seems to remove the #hash portion of the URL. I assume this is not intentional?
As you can see in my reproduction steps below, I am using maplibre-gl which maintains its map state in the URL hash automatically, so I'd like to leave it untouched.
// Current URL: http://localhost/#10/29.42/-98.47
const search = queryParam('q', ssp.string());
$search = 'foo';
// New URL: http://localhost/?q=foo
No response
Hello,
We've chatted before. Thanks again for creating this super helpful package. I'd donate to you if there was an option for it (is there?)
I wanted to report something I have been getting in my logs on any page that uses this package. I checked the stack trace and it appears that goto
is being called a total of 4 times in the main sveltekit-search-params.js
file. It's possible I have things setup in an unusual way where SvelteKit tries to execute this code on the server - I have a lot of logic about how navigation happens in my app. This happens on a page where I use debounceHistory
and a page where I don't.
I'm not sure I will be able to repro it, but I will try later today. But I think adding a if(browser) guard before the goto calls would maybe fix the issue? Even if it's not something that only occurs in edge cases.
N/A
No response
When queryParam
is used on a page that has enabled sveltekit prerendering, the build crashes. This in theory is understandable because obviously there are no query parameters during build. However, I would expect the behavior to be the same as in during SSR: I get null and wait for hydration.
Minimal reproduction repo: https://github.com/shilangyu/sveltekit-search-params-prerender
Run npm run build
to see the problem.
Error: Cannot access url.searchParams on a page with prerendering enabled
at URL.get (file:///Users/marcinwojnarowski/coding/temp/svelte-kit-prerender-query/.svelte-kit/output/server/chunks/exports.js:92:15)
at file:///Users/marcinwojnarowski/coding/temp/svelte-kit-prerender-query/.svelte-kit/output/server/entries/pages/_page.svelte.js:22:35
at sync (file:///Users/marcinwojnarowski/coding/temp/svelte-kit-prerender-query/.svelte-kit/output/server/chunks/index.js:66:22)
at file:///Users/marcinwojnarowski/coding/temp/svelte-kit-prerender-query/.svelte-kit/output/server/chunks/index.js:89:5
at Object.subscribe2 [as subscribe] (file:///Users/marcinwojnarowski/coding/temp/svelte-kit-prerender-query/.svelte-kit/output/server/chunks/index.js:36:14)
at subscribe (file:///Users/marcinwojnarowski/coding/temp/svelte-kit-prerender-query/.svelte-kit/output/server/chunks/ssr.js:25:23)
at file:///Users/marcinwojnarowski/coding/temp/svelte-kit-prerender-query/.svelte-kit/output/server/entries/pages/_page.svelte.js:49:25
at Object.$$render (file:///Users/marcinwojnarowski/coding/temp/svelte-kit-prerender-query/.svelte-kit/output/server/chunks/ssr.js:87:18)
at Object.default (file:///Users/marcinwojnarowski/coding/temp/svelte-kit-prerender-query/.svelte-kit/output/server/chunks/internal.js:80:98)
at file:///Users/marcinwojnarowski/coding/temp/svelte-kit-prerender-query/.svelte-kit/output/server/entries/fallbacks/layout.svelte.js:3:42
node:internal/event_target:1096
process.nextTick(() => { throw err; });
^
Error: 500 /
To suppress or handle this error, implement `handleHttpError` in https://kit.svelte.dev/docs/configuration#prerender
at file:///Users/marcinwojnarowski/coding/temp/svelte-kit-prerender-query/node_modules/@sveltejs/kit/src/core/config/options.js:202:13
at file:///Users/marcinwojnarowski/coding/temp/svelte-kit-prerender-query/node_modules/@sveltejs/kit/src/core/postbuild/prerender.js:65:25
at save (file:///Users/marcinwojnarowski/coding/temp/svelte-kit-prerender-query/node_modules/@sveltejs/kit/src/core/postbuild/prerender.js:403:4)
at visit (file:///Users/marcinwojnarowski/coding/temp/svelte-kit-prerender-query/node_modules/@sveltejs/kit/src/core/postbuild/prerender.js:236:3)
Node.js v21.6.1
I have a search
query string parameter bound to a search input field. Ideally, when the search input field is empty, I'd like to see the search
query string disappear from the URL. Currently, it shows ?search=
.
The current solution is this:
function nullableQueryParam<T>({
encode,
...codec
}: EncodeAndDecodeOptions<T>) {
return {
...codec,
encode(value) {
if (value === "") return undefined;
if (Array.isArray(value) && value.length === 0) return undefined;
return encode(value);
},
} as EncodeAndDecodeOptions<T>;
}
Then use it as follows:
export function getUrlSearchParamsFiltersStore() {
return queryParam<string[]>("filters", nullableQueryParam(ssp.array()));
}
see title
see title
I noticed when I go to different page routes my search params are persisting, and I think it's because I need to unsubscribe()
during an onDestroy()
lifecycle hook. Would you consider returning the subscription that you have here?
In Svelte, you can use the bind:group
feature like so:
<script lang="ts">
let selected = []
</script>
<input type="checkbox" bind:group={selected} value="2022" />
<input type="checkbox" bind:group={selected} value="2023" />
<input type="checkbox" bind:group={selected} value="2024" />
However, when attempting to apply the same technique with the (awesome! 😎) sveltekit-search-params
package, as shown:
<script lang="ts">
import { ssp, queryParam } from 'sveltekit-search-params';
const selected = queryParam('years', ssp.array());
</script>
<input type="checkbox" bind:group={$selected} value="2022" />
<input type="checkbox" bind:group={$selected} value="2023" />
<input type="checkbox" bind:group={$selected} value="2024" />
An error occurs:
TypeError: Cannot read properties of null (reading 'indexOf')
It's possible that there's an error in my implementation, or perhaps this feature isn't supported yet. Regardless, having this functionality would be fantastic.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.