How to create query parameters in Javascript? - javascript

Is there any way to create the query parameters for doing a GET request in JavaScript?
Just like in Python you have urllib.urlencode(), which takes in a dictionary (or list of two tuples) and creates a string like 'var1=value1&var2=value2'.

Here you go:
function encodeQueryData(data) {
const ret = [];
for (let d in data)
ret.push(encodeURIComponent(d) + '=' + encodeURIComponent(data[d]));
return ret.join('&');
}
Usage:
const data = { 'first name': 'George', 'last name': 'Jetson', 'age': 110 };
const querystring = encodeQueryData(data);

URLSearchParams has increasing browser support.
const data = {
var1: 'value1',
var2: 'value2'
};
const searchParams = new URLSearchParams(data);
// searchParams.toString() === 'var1=value1&var2=value2'
Node.js offers the querystring module.
const querystring = require('querystring');
const data = {
var1: 'value1',
var2: 'value2'
};
const searchParams = querystring.stringify(data);
// searchParams === 'var1=value1&var2=value2'

functional
function encodeData(data) {
return Object.keys(data).map(function(key) {
return [key, data[key]].map(encodeURIComponent).join("=");
}).join("&");
}

Zabba has provided in a comment on the currently accepted answer a suggestion that to me is the best solution: use jQuery.param().
If I use jQuery.param() on the data in the original question, then the code is simply:
const params = jQuery.param({
var1: 'value',
var2: 'value'
});
The variable params will be
"var1=value&var2=value"
For more complicated examples, inputs and outputs, see the jQuery.param() documentation.

ES2017 (ES8)
Making use of Object.entries(), which returns an array of object's [key, value] pairs. For example, for {a: 1, b: 2} it would return [['a', 1], ['b', 2]]. It is not supported (and won't be) only by IE.
Code:
const buildURLQuery = obj =>
Object.entries(obj)
.map(pair => pair.map(encodeURIComponent).join('='))
.join('&');
Example:
buildURLQuery({name: 'John', gender: 'male'});
Result:
"name=John&gender=male"

We've just released arg.js, a project aimed at solving this problem once and for all. It's traditionally been so difficult but now you can do:
var querystring = Arg.url({name: "Mat", state: "CO"});
And reading works:
var name = Arg("name");
or getting the whole lot:
var params = Arg.all();
and if you care about the difference between ?query=true and #hash=true then you can use the Arg.query() and Arg.hash() methods.

This should do the job:
const createQueryParams = params =>
Object.keys(params)
.map(k => `${k}=${encodeURI(params[k])}`)
.join('&');
Example:
const params = { name : 'John', postcode: 'W1 2DL'}
const queryParams = createQueryParams(params)
Result:
name=John&postcode=W1%202DL

If you are using Prototype there is Form.serialize
If you are using jQuery there is Ajax/serialize
I do not know of any independent functions to accomplish this, though, but a google search for it turned up some promising options if you aren't currently using a library. If you're not, though, you really should because they are heaven.

The built-in URL class provides a convenient interface for creating and parsing URLs.
There are no networking methods that require exactly a URL object, strings are good enough. So technically we don’t have to use URL. But sometimes it can be really helpful.
👇 Example
let url = new URL("https://google.com/search");
url.searchParams.set('var1', "value1");
url.searchParams.set('var2', "value2");
url.searchParams.set('var3', "value3");
url.searchParams.set('var4', "value4 has spaces");
console.log(url)

A little modification to typescript:
public encodeData(data: any): string {
return Object.keys(data).map((key) => {
return [key, data[key]].map(encodeURIComponent).join("=");
}).join("&");
}

Just like to revisit this almost 10 year old question. In this era of off-the-shelf programming, your best bet is to set your project up using a dependency manager (npm). There is an entire cottage industry of libraries out there that encode query strings and take care of all the edge cases. This is one of the more popular ones -
https://www.npmjs.com/package/query-string

Here is an example:
let my_url = new URL("https://stackoverflow.com")
my_url.pathname = "/questions"
const parameters = {
title: "just",
body: 'test'
}
Object.entries(parameters).forEach(([name, value]) => my_url.searchParams.set(name, value))
console.log(my_url.href)

I have improved the function of shog9`s to handle array values
function encodeQueryData(data) {
const ret = [];
for (let d in data) {
if (typeof data[d] === 'object' || typeof data[d] === 'array') {
for (let arrD in data[d]) {
ret.push(`${encodeURIComponent(d)}[]=${encodeURIComponent(data[d][arrD])}`)
}
} else if (typeof data[d] === 'null' || typeof data[d] === 'undefined') {
ret.push(encodeURIComponent(d))
} else {
ret.push(`${encodeURIComponent(d)}=${encodeURIComponent(data[d])}`)
}
}
return ret.join('&');
}
Example
let data = {
user: 'Mark'
fruits: ['apple', 'banana']
}
encodeQueryData(data) // user=Mark&fruits[]=apple&fruits[]=banana

By using queryencoder, you can have some nice-to-have options, such custom date formatters, nested objects and decide if a val: true will be just value or value=true.
const { encode } = require('queryencoder');
const object = {
date: new Date('1999-04-23')
};
// The result is 'date=1999-04-23'
const queryUrl = encode(object, {
dateParser: date => date.toISOString().slice(0, 10)
});

const base = "https://www.facebook.com"
const path = '/v15.0/dialog/oauth'
const params = new URLSearchParams({
client_id: clientID,
redirect_uri: redirectUri,
state: randomState,
})
const url = new URL(`${path}?${params.toString()}`, base)
Here's an example to create query parameters and build URL from base using only JavaScript built-in constructor.
This is part of Facebook Login implementation in manual approach.
According to URLSearchParams doc's example, there's a line
const new_url = new URL(`${url.origin}${url.pathname}?${new_params}`);
and I've followed that practice.
This is by far the most standardized way to build URL I believe.
I was a bit surprised that JavaScript doesn't supports query or fragment arguments in thier URL constructor still in 2023, despite It's definately worth having that.

This thread points to some code for escaping URLs in php. There's escape() and unescape() which will do most of the work, but the you need add a couple extra things.
function urlencode(str) {
str = escape(str);
str = str.replace('+', '%2B');
str = str.replace('%20', '+');
str = str.replace('*', '%2A');
str = str.replace('/', '%2F');
str = str.replace('#', '%40');
return str;
}
function urldecode(str) {
str = str.replace('+', ' ');
str = unescape(str);
return str;
}

Related

Getting an object value from props chain call

Suppose I have an object
const obj = {
key1:{
key2:{
val:'value'
}
}
}
Also I have some function that returns the path to the proper value:
func(obj,'value') //returns a string ['key1']['key2']['val']
I would like to get the 'value' with a call kind of this:
obj`${func(obj,'value')}`
It should look like
obj.key1.key2.val
But I am getting en error.
The Complexity of this stuff is for pushing the 'value' in an array with saving the tree structure
Using reduce() to return value by iterating an array of keys.
const obj = {key1:{key2:{val:'The retrieved value'}}}
// without eval()
const keyString = "['key1']['key2']['val']";
// return array of keys using regex
const keyReg = /\['(.+?)'\]/g;
const keyArr = [...keyString.matchAll(keyReg)].map(match => match[1]);
// passing obj as inital accumulator and iteratively retrieving nested value
const retrievedValue = keyArr.reduce((a, key) => (a = a[key], a),obj);
console.log(retrievedValue);
Using eval()
This is trivial with eval() but as MDN notes:
Warning: Executing JavaScript from a string is an enormous security risk. It is far too easy for a bad actor to run arbitrary code when you use eval(). See Never use eval()!, below.
const obj = {key1:{key2:{val:'The retrieved value'}}}
// Simply calling 'eval()' with the string
const keyString = "['key1']['key2']['val']";
const value1 = eval(`obj${keyString}`)
console.log(`obj${keyString}`)
console.log(value1);
// convoluted process to make it look like obj.key1.key2.val
const keyReg = /\['(.+?)'\]/g;
const keyArr = [...keyString.matchAll(keyReg)].map(match => match[1]);
const objQuery = keyArr.reduce((a, key) => (a += `.${key}`, a),`obj`);
const value2 = eval(objQuery)
console.log('');
console.log(objQuery)
console.log(value2);
// if you saved your initial string with a simple delimiter
const delimitedKeyString = "key1/key2/val";
const delimitedQuery = delimitedKeyString.split('/').join('.');
const value3 = eval(`obj.${delimitedQuery}`)
console.log('');
console.log(`obj.${delimitedQuery}`)
console.log(value3);

Parsing a templated string

I have a string like this
const str = 'map("a")to("b");map("foo")to("bar");map("alpha")to("beta");'
I wanted to parse this string to generate a json something like
[{id: 'a', map: 'b'},
{id: 'foo', map: 'bar'},
{id: 'alpha', map: 'beta'}]
I was wondering if regex is the best way to do this or if theres any utility lib I could leverage
Here's a regex that should work for your current case:
const str = 'map("a")to("b");map("foo")to("bar");map("alpha")to("beta");';
const res = str.split(";").map(e => {
const k = e.match(/map\("(.+?)"\)to\("(.+?)"\)/);
return k && k.length === 3 ? {id: k[1], map: k[2]} : null;
}).filter(e => e);
console.log(res);
The idea is to split on semicolons (a lookaround could be used to handle cases when semicolons are part of your desired key/value), then map these pairs into the desired object format based on a regex that parses the map("")to("") format. Finally, nulls are filtered out.
I'm pretty sure there is a nice regex solution which is shorter and faster, but since i'm bad at regex i solve those things like that:
const str = 'map("a")to("b");map("foo")to("bar");map("alpha")to("beta");'
const result = str.split(';').map(e => {
const parts = e.substring(3).split('to').map(item => item.replace(/\W/g, ''));
return {
id: parts[0],
map: parts[1]
};
})
console.log(result);

Converting a String to Multiple objects (javascript)

I have the following string: Jack:13,Phil:15,Lucy:12I'm trying to fetch objects from this string.
This string would have 3 people objects with their ages. How can this be achieved?
I've tried the following:
var s = 'Jack:13,Phil:15,Lucy:12'
var obj1 = eval("("+s+")");
var obj2 = JSON.parse(s);
Logging any of the obj variables returns errors. Am I missing a simple trick here? Any explanation would be appreciated, thanks.
In general, if you're doing replaces on a string to turn it into something you can pass eval or JSON.parse, that's probably not your best approach. An in particular, avoid using eval (or its cousin new Function) when you can (you certainly can here), and always avoid eval (or its cousin new Function) with untrusted input.
A pair of splits with map does it:
const s = 'Jack:13,Phil:15,Lucy:12'
const people = s.split(",")
.map(e => e.split(":"))
.map(([name, age]) => ({name, age}));
console.log(people);
...or in ES5:
var s = 'Jack:13,Phil:15,Lucy:12'
var people = s.split(",")
.map(function(e) { return e.split(":"); })
.map(function(e) { return {name: e[0], age: e[1]}; });
console.log(people);
I'm not sure why I did two maps rather than just doing the second split and creating the object in the same callback; I guess I'm thinking more and more in a "functional programming" way. I'd change it, but Eddie's answer already does it in a single map, so...
...(edit) but since it looks like you wanted separate properties rather than using the person's name like Eddie did, here's an example of the above but with just a single map:
const s = 'Jack:13,Phil:15,Lucy:12'
const people = s.split(",")
.map(e => {
const [name, age] = e.split(":");
return {name, age};
});
console.log(people);
...or in ES5:
var s = 'Jack:13,Phil:15,Lucy:12'
var people = s.split(",")
.map(function(e) {
var parts = e.split(":");
return {name: parts[0], age: parts[1]};
});
console.log(people);
You can split() the string and use map() to loop thru the array. This will return an array of objects.
var s = 'Jack:13,Phil:15,Lucy:12';
var result = s.split(',').map(o => {
let [k, v] = o.split(':');
return {[k]: v};
});
console.log(result);
If you want a single object, you can use reduce
var s = 'Jack:13,Phil:15,Lucy:12';
var result = s.split(',').reduce((c, o) => {
let [k, v] = o.split(':');
return Object.assign(c, {[k]: v});
}, {});
console.log(result);
You can try with:
const result = s.split(',')
.map(value => value.split(':'))
.reduce((acc, [name, value]) => {
acc[name] = +value;
return acc;
}, {});
Output:
{
"Jack": 13,
"Phil": 15,
"Lucy": 12
}
As I'm sure you've worked out there are many ways to do this, I thought I'd add another method
let s = 'Jack:13,Phil:15,Lucy:12'
let obj = {};
s.split(",").forEach(part => {
obj[part.split(":")[0]] = part.split(":")[1];
})
console.log(obj);
This is a simple split the string and then on each item of the new array do a split and push the results into an empty object already declared.
You could split the parts and build a new object with key/value pairs.
var string = 'Jack:13,Phil:15,Lucy:12',
result = Object.assign(...string
.split(',')
.map(s => (([k, v]) => ({ [k]: v }))(s.split(':')))
);
console.log(result);
For getting an array with objects
var string = 'Jack:13,Phil:15,Lucy:12',
result = string
.split(',')
.map(s => (([name, age]) => ({ name, age }))(s.split(':')));
console.log(result);
Easy to do with .map():
var s = 'Jack:13,Phil:15,Lucy:12';
var items = s.split(',')
.map((entry) => entry.split(':'))
.map((item) => ({name: item[0], age: item[1]}));
console.log(items);

Mapping object to key=value string in one line

Is there a way to convert this object:
{
lang: 'en-us',
episode: 12
}
To a string with the following format?
"lang=en-us&episode=12"
Much like mapping an object to a query string, where each property is a query parameter.
I can do it like this:
var parameters = [];
for(var prop in obj)
parameters.push(prop + '=' + obj[prop]);
return parameters.join('&');
But I was looking for a one-line solution. Is this possible?
PS: I cannot use jQuery and any of it utility functions. The solution must be in pure JavaScript.
You can use Array.prototype.map on the Object.keys array:
var data = {"lang": "en-us", "episode": 12};
var str = Object.keys(data).map(function (key) {
return "" + key + "=" + data[key]; // line break for wrapping only
}).join("&");
console.log(str);
With ES6, this becomes even more terse:
var data = {"lang": "en-us", "episode": 12};
var str = Object.keys(data).map(key => `${key}=${data[key]}`).join("&");
console.log(str);
You could use
var myObj ={"lang": "en-us", "episode": 12};
var str = Object.keys(myObj).map(key => key+"="+myObj[key]).join("&");
Whether or not this is any more readable is another question :)
All the other answers work perfectly,
However I've found that you can use URLSearchParams for the same thing...
var myObj = {keyOne: 'keyOneValue', keyTwo: 'keyTwoValue'};
var queryParams = new URLSearchParams(myObj).toString();
console.log(queryParams);
// keyOne=keyOneValue&keyTwo=keyTwoValue
see: https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams
Object.entries (ES6)
Object.entries returns [key, value] pairs, so we can destructure and map the pairs directly into ${key}=${value}:
Object.entries(params).map(([key, value]) => `${key}=${value}`).join('&');
// "lang=en-us&episode=12"
URLSearchParams
For the specific use case of query strings, use URLSearchParams.toString:
let searchParams = new URLSearchParams(params);
searchParams.toString();
// "lang=en-us&episode=12"
URLSearchParams provides an interface with common utility methods, e.g.:
searchParams.get('episode');
// "12"
searchParams.sort();
// "episode=12&lang=en-us"
searchParams.set('episode', 123456);
// "episode=123456&lang=en-us"
If the value contains equalTo (=) symbol, the accepted solution will not work.
Example
key1=a,key2=b,keyc=keyof=thec
accesskey=absdsfdfsa===
Solution:
Better to use Regex,
const a =
'AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;DefaultEndpointsProtocol=http;BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1;QueueEndpoint=http://127.0.0.1:10001/devstoreaccount1;TableEndpoint=http://127.0.0.1:10002/devstoreaccount1';
const output = {};
a.split(';').forEach((v, i) => {
const [key, value] = v.split(RegExp(/=(.*)/));
output[key] = value;
})
console.log(output);
output
Note: AccountKey contains == in value
{
AccountName: 'devstoreaccount1',
AccountKey: 'Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==',
DefaultEndpointsProtocol: 'http',
BlobEndpoint: 'http://127.0.0.1:10000/devstoreaccount1',
QueueEndpoint: 'http://127.0.0.1:10001/devstoreaccount1',
TableEndpoint: 'http://127.0.0.1:10002/devstoreaccount1'
}

How can I get a specific parameter from location.search? [duplicate]

This question already has answers here:
How can I get query string values in JavaScript?
(73 answers)
Closed 4 years ago.
If I had a URL such as
http://localhost/search.php?year=2008
How would I write a JavaScript function to grab the variable year and see if it contains anything?
I know it can be done with location.search but I can’t figure out how it grabs parameters.
You may use window.URL class:
new URL(location.href).searchParams.get('year')
// Returns 2008 for href = "http://localhost/search.php?year=2008".
// Or in two steps:
const params = new URL(location.href).searchParams;
const year = params.get('year');
My favorite way for getting URL params is this approach:
var parseQueryString = function() {
var str = window.location.search;
var objURL = {};
str.replace(
new RegExp( "([^?=&]+)(=([^&]*))?", "g" ),
function( $0, $1, $2, $3 ){
objURL[ $1 ] = $3;
}
);
return objURL;
};
//Example how to use it:
var params = parseQueryString();
alert(params["foo"]);
A non-regex approach, you can simply split by the character '&' and iterate through the key/value pair:
function getParameter(paramName) {
var searchString = window.location.search.substring(1),
i, val, params = searchString.split("&");
for (i=0;i<params.length;i++) {
val = params[i].split("=");
if (val[0] == paramName) {
return val[1];
}
}
return null;
}
2020 EDIT:
Nowadays, in modern browsers you can use the URLSearchParams constructor:
const params = new URLSearchParams('?year=2020&month=02&day=01')
// You can access specific parameters:
console.log(params.get('year'))
console.log(params.get('month'))
// And you can iterate over all parameters
for (const [key, value] of params) {
console.log(`Key: ${key}, Value: ${value}`);
}
This question is old and things have evolved in JavaScript.
You can now do this:
const params = {}
document.location.search.substr(1).split('&').forEach(pair => {
[key, value] = pair.split('=')
params[key] = value
})
and you get params.year that contains 2008.
You would also get other query params in your params object.
Edit: a shorter/cleaner way to do this:
const params = new Map(location.search.slice(1).split('&').map(kv => kv.split('=')))
You can then test if the year param exists with:
params.has('year') // true
Or retrieve it with:
params.get('year') // 2008
Edit 2020
You can convert URL params to an Object:
const params = location.search.slice(1).split('&').reduce((acc, s) => {
const [k, v] = s.split('=')
return Object.assign(acc, {[k]: v})
}, {})
Then it can be used as a regular JS Object:
params.year // 2008
The following uses regular expressions and searches only on the query string portion of the URL.
Most importantly, this method supports normal and array parameters as in
http://localhost/?fiz=zip&foo[]=!!=&bar=7890#hashhashhash
function getQueryParam(param) {
var result = window.location.search.match(
new RegExp("(\\?|&)" + param + "(\\[\\])?=([^&]*)")
);
return result ? result[3] : false;
}
console.log(getQueryParam("fiz"));
console.log(getQueryParam("foo"));
console.log(getQueryParam("bar"));
console.log(getQueryParam("zxcv"));
Output:
zip
!!=
7890
false
It took me a while to find the answer to this question. Most people seem to be suggesting regex solutions. I strongly prefer to use code that is tried and tested as opposed to regex that I or someone else thought up on the fly.
I use the parseUri library available here:
http://stevenlevithan.com/demo/parseuri/js/
It allows you to do exactly what you are asking for:
var uri = 'http://localhost/search.php?year=2008';
var year = uri.queryKey['year'];
// year = '2008'
function gup( name ) {
name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
var regexS = "[\\?&]"+name+"=([^&#]*)";
var regex = new RegExp( regexS );
var results = regex.exec( window.location.href );
if( results == null )
return "";
else
return results[1];
}
var year = gup("year"); // returns "2008"
The easiest way is to have
if (document.location.search.indexOf('yourtext=') >= 0) {
// your code
} else {
// what happens?
}
indexOf()
The indexOf(text) function returns
A WHOLE NUMBER BELOW 0 when the text passed in the function is not in whatever variable or string you are looking for - in this case document.location.search.
A WHOLE NUMBER EQUAL TO 0 OR HIGHER when the text passed in the function is in whatever variable or string you are looking for - in this case document.location.search.
I hope this was useful, #gumbo
A Simple One-Line Solution:
let query = Object.assign.apply(null, location.search.slice(1).split('&').map(entry => ({ [entry.split('=')[0]]: entry.split('=')[1] })));
Expanded & Explained:
// define variable
let query;
// fetch source query
query = location.search;
// skip past the '?' delimiter
query = query.slice(1);
// split source query by entry delimiter
query = query.split('&');
// replace each query entry with an object containing the query entry
query = query.map((entry) => {
// get query entry key
let key = entry.split('=')[0];
// get query entry value
let value = entry.split('=')[1];
// define query object
let container = {};
// add query entry to object
container[key] = value;
// return query object
return container;
});
// merge all query objects
query = Object.assign.apply(null, query);
I used a variant of Alex's - but needed to to convert the param appearing multiple times to an array. There seem to be many options. I didn't want rely on another library for something this simple. I suppose one of the other options posted here may be better - I adapted Alex's because of the straight forwardness.
parseQueryString = function() {
var str = window.location.search;
var objURL = {};
// local isArray - defer to underscore, as we are already using the lib
var isArray = _.isArray
str.replace(
new RegExp( "([^?=&]+)(=([^&]*))?", "g" ),
function( $0, $1, $2, $3 ){
if(objURL[ $1 ] && !isArray(objURL[ $1 ])){
// if there parameter occurs more than once, convert to an array on 2nd
var first = objURL[ $1 ]
objURL[ $1 ] = [first, $3]
} else if(objURL[ $1 ] && isArray(objURL[ $1 ])){
// if there parameter occurs more than once, add to array after 2nd
objURL[ $1 ].push($3)
}
else
{
// this is the first instance
objURL[ $1 ] = $3;
}
}
);
return objURL;
};
I played a bit with this problem and at this end I used this:
function getJsonFromUrl() {
return Object.assign(...location.search.substr(1).split("&").map(sliceProperty));
}
Object.assign to transform a list of object into one object
Spread operator ... to transform an array into a list
location.search.substr(1).split("&") to get all parameters as array of properties (foo=bar)
map walk each properties and split them into an array (either call splitProperty or sliceProperty).
splitProperty:
function splitProperty(pair) {
[key, value] = pair.split("=")
return { [key]: decodeURIComponent(value) }
}
Split by =
Deconstruct the array into an array of two elements
Return a new object with the dynamic property syntax
sliceProperty:
function sliceProperty(pair) {
const position = pair.indexOf("="),
key = pair.slice(0, position),
value = pair.slice(position + 1, pair.length);
return { [key]: decodeURIComponent(value) }
}
Set the position of =, key and value
Return a new object with the dynamic property syntax
I think splitProperty is prettier but sliceProperty is faster. Run JsPerf for more information.
Grab the params from location.search with one line:
const params = new Map(this.props.location.search.slice(1).split('&').map(param => param.split('=')))
Then, simply:
if(params.get("year")){
//year exists. do something...
} else {
//year doesn't exist. do something else...
}
ES6 answer:
const parseQueryString = (path = window.location.search) =>
path.slice(1).split('&').reduce((car, cur) => {
const [key, value] = cur.split('=')
return { ...car, [key]: value }
}, {})
for example:
parseQueryString('?foo=bar&foobar=baz')
// => {foo: "bar", foobar: "baz"}
This is what I like to do:
window.location.search
.substr(1)
.split('&')
.reduce(
function(accumulator, currentValue) {
var pair = currentValue
.split('=')
.map(function(value) {
return decodeURIComponent(value);
});
accumulator[pair[0]] = pair[1];
return accumulator;
},
{}
);
Of course you can make it more compact using modern syntax or writing everything into one line...
I leave that up to you.

Categories