Related
I have got a . (dot) separated string, from which I want to create nested JSON object. The length of the string is not fixed. For example,
var string = 'a.b.c.d';
Then my JSON object should be as following:
a: {
b: {
c:{
d: {
//Some properties here.
}
}
}
}
I've tried following code:
var packageName = "a.b.c.d"
var splitted = packageName.split('.');
var json = {};
for(var i=0;i<splitted.length-1;i++){
json[splitted[i]] = splitted[i+1];
}
But this returns
{
a: 'b',
b: 'c',
c: 'd'
}
But this is not what I want. I've also searched on google and found similar questions, but no solutions answer my problem. For example this.
A good use case for reduce
packageName = "a.b.c.d";
initProps = {hi: 'there'};
obj = packageName.split('.').reduceRight((o, x) => ({[x]: o}), initProps);
console.log(JSON.stringify(obj))
If you find loops easier to work with, a loop could be written concisely as
result = {};
ptr = result;
for (let prop of packageName.split('.'))
ptr = ptr[prop] = {};
You need to create a new object each time and attribute it to the last object created. And it goes until splitted.length, not splitted.length - 1, because you're using <, not <=.
var packageName = "a.b.c.d";
var splitted = packageName.split('.');
var json = {};
var current = json;
for (var i = 0; i < splitted.length; i++) {
current[splitted[i]] = {};
current = current[splitted[i]];
}
console.log(json);
You may use the last splittted part as property for some payload.
I suggest to keep the object reference and use a temporary variable for aceessing an creating a new property, if necessary.
Please avoid the use of JSON for not stringified objects.
var packageName = "a.b.c.d",
splitted = packageName.split('.'),
result = {},
temp = result,
i;
for (i = 0; i < splitted.length - 1; i++) {
temp[splitted[i]] = temp[splitted[i]] || {};
temp = temp[splitted[i]];
}
temp[splitted[i]] = { some: 'data' };
console.log(result);
I want to write a function such as:
function extract(template, example){
//some magic
return obj;
}
That given an input like the following:
var template = "/some/path/{param_one}/{another_param}/etc?arg1={value}";
var example = "/some/path/foo/bar/etc?arg1=baz";
Would return this object:
{param_one: "foo", another_param: "bar", value: "baz"}
I don't have control over the template nor the example (e.g. I can't change the template to be a regex with named capture groups). What I can safely assume is that the given example will match the template.
As a start, I was able to extract the keys with this:
var re = /\{(.+?)\}/g;
var match;
do {
match = re.exec(template)
if (match) {
console.log(match[1]);
}
} while (match);
I use regex and replace to solve:
function extract(template, example){
//some magic
var re = /(?:([^\{]*)\{([^\}]*)\})/g;
var result = example;
var params = [];
var match, values, obj = {};
do {
match = re.exec(template)
if (match) {
result = result.replace(match[1], '|');
params.push(match[2]);
}
} while (match);
values = result.split('|');
for(var i=0;i < params.length; i++) {
obj[params[i]] = values[i+1];
}
return obj;
}
First, it get params part and text part use regex, then it replace all text part with | and store key to params array.
Finally, it loops through params array and match value splited from above
Hope this help
I would break this into two parts - build a template object, then use that template object to parse your string(s). The following function buildTemplate(pattern) returns a template object. You can then use this object to parse as many strings as you need, for example buildTemplate(pattern).parse(string) or even var parser = buildTemplate(pattern); var parameters = parser.parse(string);.
function buildTemplate(pattern) {
return (function(pattern) {
function splitString(string) {
return string.split(/[/?&]+/);
}
var glob = {};
glob.parts = splitString(pattern).map(function(part) {
var trimmedPart = part.replace(/^\{|\}$/g, '');
var isLiteral = part.length !== trimmedPart.length + 2;
return {
isLiteral: isLiteral,
value: isLiteral ? part : trimmedPart:
};
});
glob.parse = function(string) {
var stringParts = splitString(string);
if (stringParts.length !== glob.parts.length) {
return null;
}
var params = {};
for (var i = 0; i < stringParts.length; i++) {
if (blob.parts[i].isLiteral) {
if (blob.parts[i].value !== stringParts[i]) {
return null;
}
} else {
params[blob.parts[i].value] = stringParts[i];
}
}
return params;
}
return glob;
})(pattern);
}
Note: This code is completely untested. Let me know if something doesn't work as intended.
I have array object(x) that stores json (key,value) objects. I need to make sure that x only takes json object with unique key. Below, example 'id' is the key, so i don't want to store other json objects with 'item1' key.
x = [{"id":"item1","val":"Items"},{"id":"item1","val":"Items"},{"id":"item1","val":"Items"}]
var clickId = // could be "item1", "item2"....
var found = $.inArray(clickId, x); //
if(found >=0)
{
x.splice(found,1);
}
else{
x.push(new Item(clickId, obj)); //push json object
}
would this accomplish what you're looking for? https://jsfiddle.net/gukv9arj/3/
x = [
{"id":"item1","val":"Items"},
{"id":"item1","val":"Items"},
{"id":"item2","val":"Items"}
];
var clickId = [];
var list = JSON.parse(x);
$.each(list, function(index, value){
if(clickId.indexOf(value.id) === -1){
clickId.push(value.id);
}
});
You can't use inArray() because you are searching for an object.
I'd recommend rewriting a custom find using Array.some() as follows.
var x = [{"id":"item1","val":"Items"},{"id":"item1","val":"Items"},{"id":"item1","val":"Items"}]
var clickId = "item1";
var found = x.some(function(value) {
return value.id === clickId;
});
alert(found);
Almost 6 years later i ended up in this question, but i needed to fill a bit more complex array, with objects. So i needed to add something like this.
var values = [
{value: "value1", selected: false},
{value: "value2", selected: false}
//there cannot be another object with value = "value1" within the collection.
]
So I was looking for the value data not to be repeated (in an object's array), rather than just the value in a string's array, as required in this question. This is not the first time i think in doing something like this in some JS code.
So i did the following:
let valueIndex = {};
let values = []
//I had the source data in some other and more complex array.
for (const index in assetsArray)
{
const element = assetsArray[index];
if (!valueIndex[element.value])
{
valueIndex[element.value] = true;
values.push({
value: element.value,
selected: false
});
}
}
I just use another object as an index, so the properties in an object will never be repated. This code is quite easy to read and surely is compatible with any browser. Maybe someone comes with something better. You are welcome to share!
Hopes this helps someone else.
JS objects are great tools to use for tracking unique items. If you start with an empty object, you can incrementally add keys/values. If the object already has a key for a given item, you can set it to some known value that is use used to indicate a non-unique item.
You could then loop over the object and push the unique items to an array.
var itemsObj = {};
var itemsList = [];
x = [{"id":"item1","val":"foo"},
{"id":"item2","val":"bar"},
{"id":"item1","val":"baz"},
{"id":"item1","val":"bez"}];
for (var i = 0; i < x.length; i++) {
var item = x[i];
if (itemsObj[item.id]) {
itemsObj[item.id] = "dupe";
}
else {
itemsObj[item.id] = item;
}
}
for (var myKey in itemsObj) {
if (itemsObj[myKey] !== "dupe") {
itemsList.push(itemsObj[myKey]);
}
}
console.log(itemsList);
See a working example here: https://jsbin.com/qucuso
If you want a list of items that contain only the first instance of an id, you can do this:
var itemsObj = {};
var itemsList = [];
x = [{"id":"item1","val":"foo"},
{"id":"item2","val":"bar"},
{"id":"item1","val":"baz"},
{"id":"item1","val":"bez"}];
for (var i = 0; i < x.length; i++) {
var item = x[i];
if (!itemsObj[item.id]) {
itemsObj[item.id] = item;
itemsList.push(item);
}
}
console.log(itemsList);
This is late but I did something like the following:
let MyArray = [];
MyArray._PushAndRejectDuplicate = function(el) {
if (this.indexOf(el) == -1) this.push(el)
else return;
}
MyArray._PushAndRejectDuplicate(1); // [1]
MyArray._PushAndRejectDuplicate(2); // [1,2]
MyArray._PushAndRejectDuplicate(1); // [1,2]
This is how I would do it in pure javascript.
var x = [{"id":"item1","val":"Items"},{"id":"item1","val":"Items"},{"id":"item1","val":"Items"}];
function unique(arr, comparator) {
var uniqueArr = [];
for (var i in arr) {
var found = false;
for (var j in uniqueArr) {
if (comparator instanceof Function) {
if (comparator.call(null, arr[i], uniqueArr[j])) {
found = true;
break;
}
} else {
if (arr[i] == uniqueArr[j]) {
found = true;
break;
}
}
}
if (!found) {
uniqueArr.push(arr[i]);
}
}
return uniqueArr;
};
u = unique(x, function(a,b){ return a.id == b.id; });
console.log(u);
y = [ 1,1,2,3,4,5,5,6,1];
console.log(unique(y));
Create a very readable solution with lodash.
x = _.unionBy(x, [new Item(clickId, obj)], 'id');
let x = [{id:item1,data:value},{id:item2,data:value},{id:item3,data:value}]
let newEle = {id:newItem,data:value}
let prev = x.filter(ele=>{if(ele.id!=new.id)return ele);
newArr = [...prev,newEle]
I am trying to create a javascript object like
var allUserExpiry={};
allUserExpiry[aData.userId][aData.courseId][aData.uscId] = aData;
But I am getting an error like allUserExpiry[aData.userId] undefined.
Is there a way, whereby I can set multi-level JS-Object keys? or is it important that I should go by doing allUserExpiry[aData.userId]={}, then allUserExpiry[aData.userId][aData.courseId]={} ?
Please let me know if there are any utility functions available for the same.
No, there is no way to set "multilevel keys". You need to initialize each object before trying to add properties to it.
var allUserExpiry = {};
allUserExpiry[aData.userId] = {}
allUserExpiry[aData.userId][aData.courseId] = {}
allUserExpiry[aData.userId][aData.courseId][aData.uscId] = aData;
Using Computed property names from ES6, it is possible to do:
var allUserExpiry = {
[aData.userId] = {
[aData.courseId]: {
[aData.uscId]: aData
}
}
};
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#Computed_property_names
Simply use loadash,
let object = {};
let property = "a.b.c";
let value = 1;
_.set(object, property, value); // sets property based on path
let value = _.get(object, property, default); // gets property based on path
Or you can do it:
function setByPath(obj, path, value) {
var parts = path.split('.');
var o = obj;
if (parts.length > 1) {
for (var i = 0; i < parts.length - 1; i++) {
if (!o[parts[i]])
o[parts[i]] = {};
o = o[parts[i]];
}
}
o[parts[parts.length - 1]] = value;
}
And use:
setByPath(obj, 'path.path2.path', someValue);
This approach has many weak places, but for fun... :)
Why not just do this?
var allUserExpiry={};
allUserExpiry[aData.userId] = {aData.courseId: {aData.uscId: aData}};
I have a pretty hacky but short way of doing it in IE9+ as well as real browsers.
Given var path = 'aaa.bbb.ccc.ddd.eee'; where path is what your intending to make into an object and var result = {}; will will create the object {aaa: {bbb: {ccc: {ddd: {eee: {}}}}}
result = {}
path.split('.').reduce(function(prev, e) {
var newObj = {};
prev[e] = newObj;
return newObj;
}, result);
will store the object in result.
How it works:
split('.') converts the input into ['aaa', 'bbb', 'ccc', 'ddd', 'eee']
reduce(function (...) {...}, result) runs through the array created by split, and for each entry will pass along a returned value to the next one. In our case we pass the new object through after adding the new object to the old one. This creates a chain of objects. reduce returns the last object you return inside of it, so we have to defined result beforehand.
This relies on using references so it won't be immediately clear how it works if you're expecting your code to be maintained by anyone else and should probably be avoided to be honest, but it works at least.
You can also use the following to create the initial structure:
var x = function(obj, keys) {
if (!obj) return;
var i, t;
for (i = 0; i < keys.length; i++) {
if (!t) {
t = obj[keys[i]] = {};
} else {
t[keys[i]] = {};
t = t[keys[i]];
}
}
};
var a = {};
x(a, ['A', 'B', 'C', 'D', 'E', 'F']);
Another approach without strings or array as argument.
function fillObject() {
var o = arguments[0];
for(var i = 1; i < arguments.length-1; i++) {
if(!o.hasOwnProperty(arguments[i])) {
o[arguments[i]] = {};
}
if(i < arguments.length-2) {
o = o[arguments[i]];
}else {
o[arguments[i]] = arguments[i+1]
}
}
}
var myObj = {"foo":{}};
fillObject(myObj,"back","to","the","future",2);
console.log(JSON.stringify(myObj));
// {"foo":{},"back":{"to":{"the":{"future":2}}}}
But I wouldn't use it :-) It's just for fun.
Because I don't like too much intelligent algorithm. (If it was in this category)
Using lodash you can do this easily (node exists and empty check for that node)..
var lodash = require('lodash-contrib');
function invalidateRequest(obj, param) {
var valid = true;
param.forEach(function(val) {
if(!lodash.hasPath(obj, val)) {
valid = false;
} else {
if(lodash.getPath(obj, val) == null || lodash.getPath(obj, val) == undefined || lodash.getPath(obj, val) == '') {
valid = false;
}
}
});
return valid;
}
Usage:
leaveDetails = {
"startDay": 1414998000000,
"endDay": 1415084400000,
"test": { "test1" : 1234 }
};
var validate;
validate = invalidateRequest(leaveDetails, ['startDay', 'endDay', 'test.test1']);
it will return boolean.
Another solution using reduce function (thanks Brian K).
Here we created a get/set to general proposes. The first function return the value in any level. The key is splited considering the separator. the function return the value refered from last index in the key's array
The second function will set the new value considering the last index of the splited key
the code:
function getObjectMultiLevelValue(_array,key,separator){
key = key.split(separator || '.');
var _value = JSON.parse(JSON.stringify(_array));
for(var ki in key){
_value = _value[key[ki]];
}
return _value;
}
function setObjectMultiLevelValue(_array,key,value,forcemode,separator){
key.split(separator || '.').reduce(function(prev, currKey, currIndex,keysArr) {
var newObj = {};
if(prev[currKey] && !forcemode){
newObj = prev[currKey];
}
if(keysArr[keysArr.length-1] == currKey){
newObj = value;
prev[currKey] = newObj;
}
prev[currKey] = newObj;
return newObj;
}, _array);
return _array;
}
//testing the function
//creating an array
var _someArray = {a:'a',b:'b',c:{c1:'c1',c2:{c21:'nothing here...'}}};
//a multilevel key to test
var _key = 'a,a1,a21';
//any value
var _value = 'new foo in a21 key forcing replace old path';
//here the new value will be inserted even if the path exists (forcemode=true). Using comma separator
setObjectMultiLevelValue(_someArray,_key,_value,true,',');
console.log('_someArray:');
console.log(JSON.stringify(_someArray));
//inserting another value in another key... using default separator
_key = 'c.c2.c21';
_value = 'new foo in c21 key';
setObjectMultiLevelValue(_someArray,_key,_value);
console.log('_someArray:');
console.log(JSON.stringify(_someArray));
//recovering the saved value with different separators
_key = 'a,a1,a21';
console.log(getObjectMultiLevelValue(_someArray,_key,','));
_key = 'c.c2.c21';
console.log(getObjectMultiLevelValue(_someArray,_key));
Let assume our object is
const data = {
//some other data
userInfo: {},
};
First, define a new property of that object
data.userInfo.vehicle = {};
then simply
data.userInfo.vehicle.vehicleType = state.userInfo.vehicleType;
Given the following form:
<form>
<input name="foo" value="bar">
<input name="hello" value="hello world">
</form>
I can use the $.param( .. ) construct to serialize the form:
$.param( $('form input') )
=> foo=bar&hello=hello+world
How can I deserialize the above String with JavaScript and get a hash back?
For example,
$.magicFunction("foo=bar&hello=hello+world")
=> {'foo' : 'bar', 'hello' : 'hello world'}
Reference: jQuery.param( obj ).
You should use jQuery BBQ's deparam function. It's well-tested and documented.
This is a slightly modified version of a function I wrote a while ago to do something similar.
var QueryStringToHash = function QueryStringToHash (query) {
var query_string = {};
var vars = query.split("&");
for (var i=0;i<vars.length;i++) {
var pair = vars[i].split("=");
pair[0] = decodeURIComponent(pair[0]);
pair[1] = decodeURIComponent(pair[1]);
// If first entry with this name
if (typeof query_string[pair[0]] === "undefined") {
query_string[pair[0]] = pair[1];
// If second entry with this name
} else if (typeof query_string[pair[0]] === "string") {
var arr = [ query_string[pair[0]], pair[1] ];
query_string[pair[0]] = arr;
// If third or later entry with this name
} else {
query_string[pair[0]].push(pair[1]);
}
}
return query_string;
};
How about this short functional approach?
function parseParams(str) {
return str.split('&').reduce(function (params, param) {
var paramSplit = param.split('=').map(function (value) {
return decodeURIComponent(value.replace(/\+/g, ' '));
});
params[paramSplit[0]] = paramSplit[1];
return params;
}, {});
}
Example:
parseParams("this=is&just=an&example") // Object {this: "is", just: "an", example: undefined}
My answer:
function(query){
var setValue = function(root, path, value){
if(path.length > 1){
var dir = path.shift();
if( typeof root[dir] == 'undefined' ){
root[dir] = path[0] == '' ? [] : {};
}
arguments.callee(root[dir], path, value);
}else{
if( root instanceof Array ){
root.push(value);
}else{
root[path] = value;
}
}
};
var nvp = query.split('&');
var data = {};
for( var i = 0 ; i < nvp.length ; i++ ){
var pair = nvp[i].split('=');
var name = decodeURIComponent(pair[0]);
var value = decodeURIComponent(pair[1]);
var path = name.match(/(^[^\[]+)(\[.*\]$)?/);
var first = path[1];
if(path[2]){
//case of 'array[level1]' || 'array[level1][level2]'
path = path[2].match(/(?=\[(.*)\]$)/)[1].split('][')
}else{
//case of 'name'
path = [];
}
path.unshift(first);
setValue(data, path, value);
}
return data;
}
I am using David Dorward's answer, and realized that it doesn't behave like PHP or Ruby on Rails how they parse the params:
1) a variable is only an array if it ends with [], such as ?choice[]=1&choice[]=12, not when it is ?a=1&a=2
2) when mulitple params exist with the same name, the later ones replaces the earlier ones, as on PHP servers (Ruby on Rails keep the first one and ignore the later ones), such as ?a=1&b=2&a=3
So modifying David's version, I have:
function QueryStringToHash(query) {
if (query == '') return null;
var hash = {};
var vars = query.split("&");
for (var i = 0; i < vars.length; i++) {
var pair = vars[i].split("=");
var k = decodeURIComponent(pair[0]);
var v = decodeURIComponent(pair[1]);
// If it is the first entry with this name
if (typeof hash[k] === "undefined") {
if (k.substr(k.length-2) != '[]') // not end with []. cannot use negative index as IE doesn't understand it
hash[k] = v;
else
hash[k.substr(0, k.length-2)] = [v];
// If subsequent entry with this name and not array
} else if (typeof hash[k] === "string") {
hash[k] = v; // replace it
// If subsequent entry with this name and is array
} else {
hash[k.substr(0, k.length-2)].push(v);
}
}
return hash;
};
which is tested fairly thoroughly.
I know this is an old thread, but maybe there is still some relevance in it?
Inspired by Jacky Li's good solution I tried a slight variation of my own with the objective to also be able to take care of arbitrary combinations of arrays and objects as input. I looked at how PHP would have done it and tried to get something "similar" going. Here is my code:
function getargs(str){
var ret={};
function build(urlnam,urlval,obj){ // extend the return object ...
var i,k,o=obj, x, rx=/\[([^\]]*)\]/g, idx=[urlnam.replace(rx,'')];
while (x=rx.exec(urlnam)) idx.push(x[1]);
while(true){
k=idx.shift();
if(k.trim()=='') {// key is empty: autoincremented index
if (o.constructor.name=='Array') k=o.length; // for Array
else if (o===obj ) {k=null} // for first level property name
else {k=-1; // for Object
for(i in o) if (+i>k) k=+i;
k++;
}
}
if(idx.length) {
// set up an array if the next key (idx[0]) appears to be
// numeric or empty, otherwise set up an object:
if (o[k]==null || typeof o[k]!='object') o[k]=isNaN(idx[0])?{}:[];
o=o[k]; // move on to the next level
}
else { // OK, time to store the urlval in its chosen place ...
// console.log('key',k,'val',urlval);
o[k]=urlval===""?null:urlval; break; // ... and leave the while loop.
}
}
return obj;
}
// ncnvt: is a flag that governs the conversion of
// numeric strings into numbers
var ncnvt=true,i,k,p,v,argarr=[],
ar=(str||window.location.search.substring(1)).split("&"),
l=ar.length;
for (i=0;i<l;i++) {if (ar[i]==="") continue;
p=ar[i].split("=");k=decodeURIComponent(p[0]);
v=p[1];v=(v!=null)?decodeURIComponent(v.replace(/\+/g,'%20')):'';
if (ncnvt && v.trim()>"" && !isNaN(v)) v-=0;
argarr.push([k,v]); // array: key-value-pairs of all arguments
}
for (i=0,l=argarr.length;i<l;i++) build(argarr[i][0],argarr[i][1],ret);
return ret;
}
If the function is called without the str-argument it will assume window.location.search.slice(1) as input.
Some examples:
['a=1&a=2', // 1
'x[y][0][z][]=1', // 2
'hello=[%22world%22]&world=hello', // 3
'a=1&a=2&&b&c=3&d=&=e&', // 4
'fld[2][]=2&fld[][]=3&fld[3][]=4&fld[]=bb&fld[]=cc', // 5
$.param({a:[[1,2],[3,4],{aa:'one',bb:'two'},[5,6]]}), // 6
'a[]=hi&a[]=2&a[3][]=7&a[3][]=99&a[]=13',// 7
'a[x]=hi&a[]=2&a[3][]=7&a[3][]=99&a[]=13'// 8
].map(function(v){return JSON.stringify(getargs(v));}).join('\n')
results in
{"a":2} // 1
{"x":{"y":[{"z":[1]}]}} // 2
{"hello":"[\"world\"]","world":"hello"} // 3
{"a":2,"b":null,"c":3,"d":null,"null":"e"} // 4 = { a: 2, b: null, c: 3, d: null, null: "e" }
{"fld":[null,null,[2],[3,4],"bb","cc"]} // 5
{"a":[[1,2],[3,4],{"aa":"one","bb":"two"},[5,6]]} // 6
{"a":["hi",2,null,[7,99],13]} // 7
{"a":{"0":2,"3":[7,99],"4":13,"x":"hi"}} // 8
Whereas Jacky Li's solution would produce the outer container for a as a plain object
{a:{"0":["1","2"],"1":["3","4"],"2":["5","6"]}} // 6: JackyLi's output
getargs() looks at the first given index for any level to determine whether this level will be an object (non-numeric index) or an array (numeric or empty), thus resulting in the output as shown in the listing bove (no. 6).
If the current object is an array then nulls get inserted wherever necessary to represent empty positions. Arrays are always consecutively numbered and 0-based).
Note, that in the example no. 8 the "autoincrement" for empty indices still works, even though we are dealing with an object now and not an array.
As far as I have tested it, my getargs() behaves pretty much identically to Chriss Roger's great jQuery $.deparam() plugin mentioned in the accepted answer. The main difference is that getargs runs without jQuery and that it does autoincrement in objects while $.deparam() will not do that:
JSON.stringify($.deparam('a[x]=hi&a[]=2&a[3][]=7&a[3][]=99&a[]=13').a);
results in
{"3":["7","99"],"x":"hi","undefined":"13"}
In $.deparam() the index [] is interpreted as an undefined instead of an autoincremented numerical index.
Here's how you could create a new jQuery function:
jQuery.unparam = function (value) {
var
// Object that holds names => values.
params = {},
// Get query string pieces (separated by &)
pieces = value.split('&'),
// Temporary variables used in loop.
pair, i, l;
// Loop through query string pieces and assign params.
for (i = 0, l = pieces.length; i < l; i++) {
pair = pieces[i].split('=', 2);
// Repeated parameters with the same name are overwritten. Parameters
// with no value get set to boolean true.
params[decodeURIComponent(pair[0])] = (pair.length == 2 ?
decodeURIComponent(pair[1].replace(/\+/g, ' ')) : true);
}
return params;
};
Thanks to him http://james.padolsey.com/javascript/parsing-urls-with-the-dom/
Pretty easy :D
function params_unserialize(p){
var ret = {},
seg = p.replace(/^\?/,'').split('&'),
len = seg.length, i = 0, s;
for (;i<len;i++) {
if (!seg[i]) { continue; }
s = seg[i].split('=');
ret[s[0]] = s[1];
}
return ret;}
This is really old question, but as i have coming - other people may coming to this post, and i want to a bit refresh this theme. Today no need to make custom solutions - there is URLSearchParams interface.
var paramsString = "q=URLUtils.searchParams&topic=api";
var searchParams = new URLSearchParams(paramsString);
//Iterate the search parameters.
for (let p of searchParams) {
console.log(p);
}
The only one limitation i know - this feature not supported in IE / Edge.
Here's my JavaScript implementation which I use in a server-side JScript ASP Classic page (demo):
// Transforms a query string in the form x[y][0][z][]=1 into {x:{y:[{z:[1]}]}}
function parseJQueryParams(p) {
var params = {};
var pairs = p.split('&');
for (var i=0; i<pairs.length; i++) {
var pair = pairs[i].split('=');
var indices = [];
var name = decodeURIComponent(pair[0]),
value = decodeURIComponent(pair[1]);
var name = name.replace(/\[([^\]]*)\]/g,
function(k, idx) { indices.push(idx); return ""; });
indices.unshift(name);
var o = params;
for (var j=0; j<indices.length-1; j++) {
var idx = indices[j];
var nextIdx = indices[j+1];
if (!o[idx]) {
if ((nextIdx == "") || (/^[0-9]+$/.test(nextIdx)))
o[idx] = [];
else
o[idx] = {};
}
o = o[idx];
}
idx = indices[indices.length-1];
if (idx == "") {
o.push(value);
}
else {
o[idx] = value;
}
}
return params;
}
I came up with this solution, which behaves like the .Net function HttpUtility.ParseQueryString.
In the result, the query string parameters are store in properties as lists of values, so that qsObj["param"] will be the same as calling GetValues("param") in .Net.
I hope you like it. JQuery not required.
var parseQueryString = function (querystring) {
var qsObj = new Object();
if (querystring) {
var parts = querystring.replace(/\?/, "").split("&");
var up = function (k, v) {
var a = qsObj[k];
if (typeof a == "undefined") {
qsObj[k] = [v];
}
else if (a instanceof Array) {
a.push(v);
}
};
for (var i in parts) {
var part = parts[i];
var kv = part.split('=');
if (kv.length == 1) {
var v = decodeURIComponent(kv[0] || "");
up(null, v);
}
else if (kv.length > 1) {
var k = decodeURIComponent(kv[0] || "");
var v = decodeURIComponent(kv[1] || "");
up(k, v);
}
}
}
return qsObj;
};
Here is how to use it:
var qsObj = parseQueryString("a=1&a=2&&b&c=3&d=&=e&");
To preview the result in the console juste type in:
JSON.stringify(qsObj)
Output:
"{"a":["1","2"],"null":["","b",""],"c":["3"],"d":[""],"":["e"]}"
There's a beautiful one-liner over at CSS-Tricks (original source from Nicholas Ortenzio):
function getQueryParameters(str) {
return (str || document.location.search).replace(/(^\?)/,'').split("&").map(function(n){return n = n.split("="),this[n[0]] = n[1],this}.bind({}))[0];
}
The really clever part is how it uses the anonymous function's this object, adding a key/value pair for each of the queries in the string. That said, there's some room for improvement. I've modified it a bit below, with the following changes:
Added handling of empty strings and non-string input.
Handled URI-encoded strings (%40->#, etc).
Removed the default use of document.location.search when the input was empty.
Changed the name, made it more readable, added comments.
function deparam(str) {
// Uses an empty 'this' to build up the results internally
function splitQuery(query) {
query = query.split('=').map(decodeURIComponent);
this[query[0]] = query[1];
return this;
}
// Catch bad input
if (!str || !(typeof str === 'string' || str instanceof String))
return {};
// Split the string, run splitQuery on each piece, and return 'this'
var queries = str.replace(/(^\?)/,'').split('&');
return queries.map(splitQuery.bind({}))[0];
}
use this :
// convert query string to json object
var queryString = "cat=3&sort=1&page=1";
queryString
.split("&")
.forEach((item) => {
const prop = item.split("=");
filter[prop[0]] = prop[1];
});
console.log(queryString);
This is my version in Coffeescript.
Also works for url like
http://localhost:4567/index.html?hello=[%22world%22]&world=hello#/home
getQueryString: (url)->
return null if typeof url isnt 'string' or url.indexOf("http") is -1
split = url.split "?"
return null if split.length < 2
path = split[1]
hash_pos = path.indexOf "#"
path = path[0...hash_pos] if hash_pos isnt -1
data = path.split "&"
ret = {}
for d in data
[name, val] = d.split "="
name = decodeURIComponent name
val = decodeURIComponent val
try
ret[name] = JSON.parse val
catch error
ret[name] = val
return ret
Here's a simple & compact one if you only want to quickly get the parameters from a GET request:
function httpGet() {
var a={},b,i,q=location.search.replace(/^\?/,"").split(/\&/);
for(i in q) if(q[i]) {b=q[i].split("=");if(b[0]) a[b[0]]=
decodeURIComponent(b[1]).replace(/\+/g," ");} return a;
}
It converts
something?aa=1&bb=2&cc=3
into an object like
{aa:1,bb:2,cc:3}
Creates a serialized representation of an array or object (can be used as URL query string for AJAX requests).
<button id='param'>GET</button>
<div id="show"></div>
<script>
$('#param').click(function () {
var personObj = new Object();
personObj.firstname = "vishal"
personObj.lastname = "pambhar";
document.getElementById('show').innerHTML=$.param(`personObj`));
});
</script>
output:firstname=vishal&lastname=pambhar
answers could use a bit of jQuery elegance:
(function($) {
var re = /([^&=]+)=?([^&]*)/g;
var decodeRE = /\+/g; // Regex for replacing addition symbol with a space
var decode = function (str) {return decodeURIComponent( str.replace(decodeRE, " ") );};
$.parseParams = function(query) {
var params = {}, e;
while ( e = re.exec(query) ) {
var k = decode( e[1] ), v = decode( e[2] );
if (k.substring(k.length - 2) === '[]') {
k = k.substring(0, k.length - 2);
(params[k] || (params[k] = [])).push(v);
}
else params[k] = v;
}
return params;
};
})(jQuery);
fork at https://gist.github.com/956897
You can use the function .serializeArray() (Link) of jQuery itself. This function returns an array of key-value pair. Result example:
[
{ name: "id", value: "1" },
{ name: "version", value: "100" }
]