0

I have a button in body that once clicked, it should add an extra query parameter in the URL.

let addParam;
const button = document.createElement("BUTTON");
button.textContent = "Add";
document.body.prepend(button);

button.addEventListener("click", () => {
  const url = new URL(window.location.href);
  url.searchParams.set("param", "value");

  window.history.pushState({ path: url.href }, "", url.href);
  addParam = addParam ? false : true;
});

It works fine, the problem is that the current URL contains already a query parameter in the form of ?path=path/to/file, so when we set another parameter with set(key, value), it changes the ?path=path/to/file to ?path=path%2Fto%2Ffile. Is there a way I can prevent that from happening and keeping the original URL?

2
  • 1
    path%2Fto%2Ffile is perfectly valid. It is properly encoded! If whatever is using that value has a problem with it, then code should be fixed to decode it properly. Commented Feb 16, 2022 at 13:52
  • Side note: The more idiomatic way to write addParam = addParam ? false : true; is addParam = !addParam; :-) Commented Feb 17, 2022 at 6:57

1 Answer 1

1

Note that both URLs mean the same thing. I'm guessing you prefer the one with / instead of the encoded form of it because it's more obvious to people reading the URL.

This may vary by browser, but on Chromium-based browsers it seems that it keeps the / if it's in the URL you pass to pushState. It's the URLSearchParams that's encoding the /.

I originally posted a solution doing string concatenation with encodeURIComponent instead, but my solution was doing an append, not a set. Your code is using set. Fortunately I'd also included a second solution: You can convert %2F to / after adding to the search params and converting them to a string:

const { origin, pathname, search } = window.location;
const searchParams = new URLSearchParams(search);
searchParams.set("param", "value");
const paramsString = searchParams.toString().replace(/%2f/gi, "/");
const url = `${origin}${pathname}?${paramsString}`;

window.history.pushState({ path: url }, "", url);
addParam = addParam ? false : true;

Note that I don't advocate this. I'd stick with the code you have. But it's your project, so you get to decide. :-)

Sign up to request clarification or add additional context in comments.

7 Comments

Turns out no need to string check, new URL accepts Location var url = new URL(window.location); url.searchParams.append('data', 'value')
@savageGoat - I'm afraid I don't know what you mean by that. But note that set and append do different things. And thank you for noting it, because my first code block does append, but the OP is using set. I'd best fix that.
I mean no need to pass a string like window.location.href, window.location is a Location type object but the Url constructor accepts the Location object so it removes all the problems related to the parameters
@savageGoat - The problem isn't in that part, it's converting back to string after updating the params. That's when / is converted to %2F.
You are right, my bad. Array.from(url.searchParams.entries()) returns the path but as soon as you pass it as encoded you still have to decode the path
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.