How to get value of URL query parameter with dynamic name? - javascript

I need to extract the value of a query parameter in a URL, but the parameter changes on each page.
For example, I want to get the color variable, but it always changes based on the productID. In this case it is 'dwvar_2000440926_color' but for another product it will be 'dwvar_545240926_color'. _color stays consistent, so I'd like to key off that:
https://www.example.com/us/2000440926.html?dwvar_2000440926_color=02
Thanks!

Basic regular expression would work
const myURL = new URL("https://www.example.com/us/2000440926.html?dwvar_2000440926_color=02")
console.log(myURL.search.match(/_color=([^&]+)/)[1]);
// more specfic
console.log(myURL.search.match(/dwvar_\d+_color=([^&]+)/)[1]);

You should use regex. Based on the description of the URL behavior you described you could do something like this:
const url = new URL("https://www.example.com/us/2000440926.html?dwvar_2000440926_color=02");
// Now url.search contains your query parameters.
// We gonna apply the regex on it to capturing the color id
let matches = url.search.match(/dwvar_\d+_color=(\d+)/)
// `matches` now contains the captured groups
console.log(matches[1])
// log : 02

Assuming that 1) you want to do this on the client side 2) the color param always begins with dwvar as shown in your example and 3) that there is never more than one dwvar param, you can use the following javascript:
let searchParams = new URLSearchParams(document.location.search);
searchParams.forEach((param_value, param_name) => {
if (param_name.indexOf('dwvar') == 0) {
console.log(param_value)
}
})

window.location.search.slice(1).split('&').reduce((acc, it) => {
const [key, val] = it.split('=');
return {
...acc,
[key]: val,
};
}, {});

Related

Javascript does not recognise two url parameters as equal even though they are equal

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=%23FFFFFF". 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%2520USB%25203%2520ports=Yes" , but when I try to change the value to "No" in the for some reason my javascript thinks that "With%2520USB%25203%2520ports" is not the same as "With%2520USB%25203%2520ports". 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;
};
I think you're overcomplicating things.
URLSearchParams deals with decoding and encoding strings by itself, so doing encodeURIComponent 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%20USB%203%20ports=Yes', 'With USB 3 ports', 'Heck yeah'));
console.log(mangleParams('?With%20USB%203%20ports=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 %20s are also normalized to +es, and all encoding works as it should).

Assign values from one set of key/value pairs to keys of another?

I'm working with the outputs of an Intranet I don't control.
I have this string:
let template = 'LAWYER=|FIRM=|SUIT_DESCRIPTION=|DEF_COMMENT=|PLF_COMMENT=|';
It goes on longer, but that's the pattern.
Now there's another similar string, but with data assigned, as in this example:
let current= 'FIRM=Smith and Wesson LLP|SUIT_DESCRIPTION=It\'s a royal mess|PLF_COMMENT=some freeform text|LAWYER=Bob Smith';
Now, notice that not every element in template is necessarily represented in current, and the order may be different (if the latter fact is a big deal, I can ensure the order is the same).
What I'm trying to do, is take every element that is in current, and populate the matching element in template, if it exists. (or, alternatively and potentially preferred, insert every non-matching element in template into current, but ideally in the same order as template).
Using the date above, the result I'm looking for is:
result = 'LAWYER=Bob Smith|FIRM=Smith and Wesson LLP|SUIT_DESCRIPTION=It\'s a royal mess|DEF_COMMENT=|PLF_COMMENT=some freeform text|';
I'm not very accomplished with JavaScript :(
I tried various things in JSFiddle using split() and match() but I just made a mess of it.
// Convert the template to an array of keys
const getKeys = str => str.split('|').map(entry => entry.split('=')[0]);
// Convert the data to an object
const toObj = str => Object.fromEntries(str.split('|').map(entry => entry.split('=')));
// Reconcile the data with the template
const compile = (templateStr, dataStr) => {
const keys = getKeys(templateStr);
const data = toObj(dataStr);
return keys.reduce((results, key) => {
if(key) results.push([key, data[key] ?? '']);
return results;
}, []);
};
// Convert the results back into a string
const toString = data => data.map(entry => entry.join('=')).join('|') + '|';
// And then a test
let template = 'LAWYER=|FIRM=|SUIT_DESCRIPTION=|DEF_COMMENT=|PLF_COMMENT=|';
let current = 'FIRM=Smith and Wesson LLP|SUIT_DESCRIPTION=It\'s a royal mess|PLF_COMMENT=some freeform text|LAWYER=Bob Smith';
console.log(toString(compile(template, current)));

Split out props.location.search value

I'm trying to split out the values from props.location.search in React/Redux. I've successfully obtained the mixOne split however I can't seem to return the value of quantity. Here's my code:
const mixOne = props.location.search
? String(props.location.search.split("mixOne=")[1])
: "None";
const quantity = props.location.search
? Number(props.location.search.split("=")[1])
: 1;
And here's the URL that gets generated:
const addToCartHandler = () => {
props.history.push(
`/Cart/${productId}?quantity=${quantity}?mixOne=${mixOne}`
);
};
As you can see quantity returns null, when I need the value selected
props.location.search.split("=") on "?quantity=1?mixOne=Grape" would return [ '?quantity', '1?mixOne', 'Grape' ] since the next = is not until after mixOne.
There's a few different fixes here.
Your query string is invalid– a ? denotes the start of the query string. Separate parameters should be split up using & ampersand characters. It should look like this: ?quantity=1&mixOne=Grape
If you follow the standard here, you can then split it two ways: by = and then by & to get the different parameters. However, there is an easier way.
Using the new-ish URLSearchParams API, you can parse your parameters in a predictable way:
// Use the constructor with your `props.location.search`
const queryParams = new URLSearchParams(props.location.search);
// Use the getters to grab a specific value
const quantity = queryParams.get("quantity");
// Ensure it's a number for safety
const quantityNum = Number(quantity);
// ... the rest of your code here
The query is wrong. You're using double question marks. The second ? should be replaced with &.
?quantity=1&mixOne=Grape

How to pull conditional values from lists inside javascript objects

I have an object, with a list inside each key. What is the best way of returning the key, if the url string matches what's in the array.
For example in the code below, 'entertainment' would be returned as "/video" is in the entertainment array.
const url = "https://example.com/video";
const verticalList = {
autos:[],
entertainment:["/video", "/tech"],
foodanddrink:[],
healthandfitness:[],
homepage:["/home"],
lifestyle:["/ideas", "/executive-life"],
money:["/money-markets",],
news:["/briefing"],
sports:[],
travel:[],
weather:[]
}
You can use Object.entries to get a list of key-value pairs from your object and then run Array.filter to compare values against your url. In the last step you have to run Array.map to retrieve corresponding keys. String.includes can be used to check if one string is a substring of another.
const url = "https://example.com/video";
const verticalList = {
autos:[],
entertainment:["/video", "/tech"],
foodanddrink:[],
healthandfitness:[],
homepage:["/home"],
lifestyle:["/ideas", "/executive-life"],
money:["/money-markets",],
news:["/briefing"],
sports:[],
travel:[],
weather:[]
}
let matches = Object.entries(verticalList)
.filter(([key,value]) => value.some(x => url.includes(x)))
.map(([key,value]) => key);
console.log(matches)

How to parse url and remove specific parameters

I would like to parse a url query string and filter and remove specific parameters.
Say the url is: www.test.com?id=123&location-texas&color=blue&event=new
And the query string : ?id=123&location-texas&color=blue&event=new
I would like to always remove the parameters id={} and color={}.
The url may or may not contain either id or color params.
The value of those parameters are not always the same but I always want to strip id and color from the query string.
I tried the following – I believe I am on the right track but need some assistance finishing up
const test = decodeURIComponent(qs.query).split('?')[1].split('&')
.filter(param => param !== id='123' || param !== color='blue' );
I would like to reconstruct the filtered array and make it :
www.test.com?location-texas&event=new
I think you can use replace
query.replace(/(\w+)=\w*/gi, (m, p) => {
if (p === 'id' || p === 'color') return ''
return m
})
More information about replace
Or just use URLSearchParams here

Categories