I am using React.js and trying to filter store products based on the parameters that the user has chosen from a set of . When clicking on an input, "onChange" fires a function that takes the name and the value, encodes it, and puts it into the URL search query as a key/value pair.
Everything is working fine, except in one instance. When the user changes their mind and picks a different answer in the , my javascript code is supposed to:
- Get the current URL parameters,
- Check if the name is already in the URL param as a key,
- If it already is inside the URL param, don't add a new param, instead change the value of the key,
- Take the new set of URL parameters and use those instead.
The good news is that this works for most key/pairs. For example:
- { Color: #fffff } would look like this in the URL "?Color=#FFFFFF". If the user changed the color the URL parameter also changed.
But...
- I have a name "WITH USB 3 PORTS" that looks like this, when added to the URL param - "?With%20USB%203%20ports=Yes" , but when I try to change the value to "No" in the for some reason my javascript thinks that "With%20USB%203%20ports" is not the same as "With%20USB%203%20ports". It does not do this for "Color" or any other key/value pair.
Can anyone explain why this might be the case and how to stop this from happening?
To give some more context, I use:
- window.location.search -> to get the URL params
- encodeURIComponent() -> to prepare the values to be used a key/value pairs
- new URLSearchParams() -> to create the new params
- window.location.href -> to refer the user to the new URL (I will later use history.pushState())
UPDATE #1
Based on @Cerbrus recommendation, I added the code that creates this issue.
//* Change the url params when the user changes the filter inputs
changeUrlParam = () => {
//* Prepare localhost variable
const baseUrl = 'http://localhost:3000'
//* Get current path name
const pathName = window.location.pathname;
//* Get current url parameters if any
const urlQuery = window.location.search;
const pureParam = urlQuery.replace('?', '');
//* Create a new param
const params = urlQuery.length < 1 ? new URLSearchParams() : new URLSearchParams(pureParam);
//* Prepare the value/key pair
const key = encodeURIComponent('With Usb 3 Ports');
const value = 'Yes';
//* If the params - ARE NOT SET
if(urlQuery.length < 1) {
//* Apend new value to it
params.append(key, value);
//* If the params - ARE SET
} else {
//* Check if the param in question is already set
const paramTest = urlQuery.includes(key);
//* If present - change it
if(paramTest === true) {
//* Change the old value to the new value
params.set(key, value);
//* If not present - apend it
} else {
//* Add the new value to the exsisting param
params.append(key, value);
}
}
//* Prepare the new url
const newUrl = baseUrl pathName '?' params.toString();
//* Go to the new url
return window.location.href = newUrl;
};
CodePudding user response:
I think you're overcomplicating things.
URLSearchParams
deals with decoding and encoding strings by itself, so doingencodeURIComponent
confuses it (indeed, a double-encoded URI component isn't the same as the non-encoded one)- The whole exists/set/append thing seems to be a no-op; just
set
the single value you need.
Here's a standalone function; replace the search
argument in the invocation(s) with window.location.search
when you'd use it in your component.
function mangleParams(search, key, value) {
const params = new URLSearchParams(search.replace(/^\?/, ''));
params.set(key, value);
return params.toString();
}
console.log(mangleParams('', 'With USB 3 ports', 'No'));
console.log(mangleParams('?With USB 3 ports=Yes', 'With USB 3 ports', 'Heck yeah'));
console.log(mangleParams('?With USB 3 ports=Yes&Other feature=Sure', 'With USB 3 ports', 'Nice'));
This outputs
With USB 3 ports=No
With USB 3 ports=Heck yeah
With USB 3 ports=Nice&Other feature=Sure
(so the s are also normalized to es, and all encoding works as it should).