Skip to content

Commit 944157b

Browse files
committed
[feat] removeQueryparam
1 parent fc25b81 commit 944157b

File tree

2 files changed

+52
-16
lines changed

2 files changed

+52
-16
lines changed

src/lib/Router.svelte

Lines changed: 51 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,14 @@
6565
6666
function _resolvePath(to) {
6767
let newFullPath;
68-
if (to.startsWith('/')) { // Absolute within the base
69-
newFullPath = (router.base.replace(/\/$/, '') + to).replace(/\/\//g, '/');
68+
if (to.startsWith('/')) { // Path starts with a slash
69+
if (router.base !== '/' && (to === router.base || to.startsWith(router.base + '/'))) {
70+
// 'to' is an absolute path that already includes the base of this nested router
71+
newFullPath = to;
72+
} else {
73+
// 'to' is absolute relative to this router's base, or this is the root router
74+
newFullPath = (router.base.replace(/\/$/, '') + to).replace(/\/\//g, '/');
75+
}
7076
} else { // Relative to current path within the base
7177
const currentDir = router.path.substring(0, router.path.lastIndexOf('/') + 1);
7278
newFullPath = (router.base.replace(/\/$/, '') + '/' + currentDir + to).replace(/\/\//g, '/');
@@ -85,19 +91,19 @@
8591
return newFullPath.replace(/\/\//g, '/') || '/';
8692
}
8793
88-
async function _runGuards(toFullPath, fromFullPath, navigationAction) {
94+
async function _runGuards(toFullPath, fromFullPath, toQueryForGuards, navigationAction) { // Added toQueryForGuards
8995
if (router.beforeEach.length === 0) {
9096
navigationAction();
9197
return;
9298
}
9399
94-
const toQuery = typeof window !== 'undefined' ? _parseQuery(window.location.search) : {}; // Or parse from toFullPath if it includes query
100+
// const toQuery = typeof window !== 'undefined' ? _parseQuery(window.location.search) : {}; // OLD
95101
const fromQuery = router.fromPath ? _parseQuery(new URL(router.fromPath, window.location.origin).search) : {};
96102
97103
// Extract params - this is tricky without knowing the matching route yet.
98104
// For guards, `params` might be less critical or require a preliminary match.
99105
// For now, passing empty params. A more advanced version could pre-match.
100-
const toRouteInfo = { path: toFullPath, params: {}, query: toQuery };
106+
const toRouteInfo = { path: toFullPath, params: {}, query: toQueryForGuards }; // Use passed toQueryForGuards
101107
const fromRouteInfo = router.fromPath ? { path: fromFullPath, params: {}, query: fromQuery } : null;
102108
103109
let i = 0;
@@ -144,6 +150,27 @@
144150
// If url prop was used, initialQuery has it. Otherwise, it's {}.
145151
}
146152
}
153+
154+
function removeQueryParams(keysToRemove) {
155+
if (typeof window !== 'undefined') {
156+
const currentSearch = window.location.search; // Get current query from actual URL
157+
const params = new URLSearchParams(currentSearch);
158+
159+
keysToRemove.forEach(key => {
160+
params.delete(key);
161+
});
162+
163+
const newSearchString = params.toString();
164+
const newQueryPart = newSearchString ? `?${newSearchString}` : '';
165+
166+
// Use the router's own navigate method.
167+
// router.path is the path relative to this router's base.
168+
// We pass the current relative path along with the new query string.
169+
// This ensures guards are run and state is updated consistently.
170+
// Using replace: true is often better for query-only changes.
171+
router.navigate(router.path + newQueryPart, { replace: true });
172+
}
173+
}
147174
148175
// This function is called by popstate or after successful guards in navigate
149176
function _performUpdate(fullPathToNavigate) {
@@ -155,32 +182,39 @@
155182
async function handlePopState() {
156183
if (typeof window !== 'undefined') {
157184
const targetFullPath = window.location.pathname; // This includes path only
185+
const currentQuery = _parseQuery(window.location.search); // Parse query at the time of popstate
158186
// Query will be re-parsed from window.location.search in _updateRouterState
159-
await _runGuards(targetFullPath, router.fullPath, () => {
187+
await _runGuards(targetFullPath, router.fullPath, currentQuery, () => { // Pass currentQuery
160188
_performUpdate(targetFullPath);
161189
});
162190
}
163191
}
164192
165193
async function navigate(to, { replace = false } = {}) {
166194
if (typeof window !== 'undefined') {
167-
const targetFullPath = _resolvePath(to); // Resolves path part of 'to'
168-
let targetSearch = window.location.search; // Default to current search query
169-
170-
// If 'to' includes a query string, use that instead.
171-
const toParts = to.split('?');
172-
if (toParts.length > 1) {
173-
targetSearch = '?' + toParts[1];
195+
let pathInput = to;
196+
let searchInput = ''; // e.g., "?foo=bar" or ""
197+
const queryIndex = to.indexOf('?');
198+
if (queryIndex !== -1) {
199+
pathInput = to.substring(0, queryIndex);
200+
searchInput = to.substring(queryIndex);
174201
}
175-
176-
await _runGuards(targetFullPath, router.fullPath, () => {
202+
203+
const targetFullPath = _resolvePath(pathInput); // pathInput is now path-only
204+
const targetSearch = searchInput; // searchInput is query from 'to', or empty
205+
206+
const toQueryForGuards = _parseQuery(targetSearch); // Parse the query we intend to navigate to
207+
208+
await _runGuards(targetFullPath, router.fullPath, toQueryForGuards, () => {
177209
router.fromPath = router.fullPath; // Set fromPath before history change
178210
if (replace) {
179211
window.history.replaceState({}, "", targetFullPath + targetSearch);
180212
} else {
181213
window.history.pushState({}, "", targetFullPath + targetSearch);
182214
}
183-
_performUpdate(targetFullPath); // Update internal state after history change. _updateRouterState will parse new search.
215+
// _performUpdate will use targetFullPath and then re-read window.location.search
216+
// which is fine as history API has just updated it.
217+
_performUpdate(targetFullPath);
184218
});
185219
}
186220
}
@@ -207,6 +241,7 @@
207241
router.navigate = navigate;
208242
router.getQueryParam = (key) => router.query[key];
209243
router.hasQueryParam = (key) => Object.prototype.hasOwnProperty.call(router.query, key);
244+
router.removeQueryParams = removeQueryParams;
210245
211246
setContext('router', router);
212247
</script>

src/lib/context.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export interface RouterContext {
1313
navigate: (to: string, options?: { replace?: boolean }) => void;
1414
getQueryParam: (key: string) => string | undefined;
1515
hasQueryParam: (key: string) => boolean;
16+
removeQueryParams: (keys: string[]) => void;
1617
}
1718

1819
export function useTinyRouter(): RouterContext;

0 commit comments

Comments
 (0)