Skip to content

Instantly share code, notes, and snippets.

@cmacrander
Created November 11, 2015 19:30
Show Gist options
  • Save cmacrander/fdacbca907e4d2995d1a to your computer and use it in GitHub Desktop.
Save cmacrander/fdacbca907e4d2995d1a to your computer and use it in GitHub Desktop.
queryStringToObject
// Read query string parameters as a javascript object.
//
// Not tested for:
//
// * Mixing bracketed and non-bracketed keys
// * Indexed brackets
// * Nested lists
//
// Some examples (See unit tests below for full details):
//
// | query string | result |
// |--------------|--------------------|
// | undefined | uses current URL |
// | ? | {} |
// | ?a | {a: undefined} |
// | ?a= | {a: undefined} |
// | ?a=1&b=2 | {a: 1, b: 2} |
// | a=1&b=2 | {a: 1, b: 2} |
// | ?a[]=1&b=2 | {a: [1], b: 2} |
// | ?a=1&a=2 | {a: [1, 2]} |
// | ?a[]=1&a[]=2 | {a: [1, 2]} |
// | ?a[]=1&a=2 | undefined behavior |
// | ?a[1]=1 | undefined behavior |
// | ?a[][]=1 | undefined behavior |
var queryStringToObject = function (queryString) {
var params = {};
// Allow for easy invocation in the default case.
if (queryString === undefined) {
queryString = window.location.search;
}
// Leading question mark optional.
if (queryString.charAt(0) === '?') {
queryString = queryString.substring(1);
}
// Quick return for empty query string.
if (queryString === '') {
return params;
}
// Separate the query string into key-value pairs.
// Be careful with split! ''.split('&') gets you ['']
var pairStrings = queryString.indexOf('&') === -1 ?
[queryString] : queryString.split('&');
// Add each key-value pair to the params object.
pairStrings.forEach(function (pairStr) {
// Split up the key and value, decoding URL escaping.
var pair = pairStr.split('='),
key = decodeURIComponent(pair[0]),
value = pair[1] ? decodeURIComponent(pair[1]) : undefined,
// A key becomes a list if either 1) it repeats or 2) it ends in [].
keyIsList = false;
// Check for bracket notation.
if (key.substr(-2) === '[]') {
keyIsList = true;
key = key.substr(0, key.length - 2);
}
// Check for repeats.
if (key in params && !(params[key] instanceof Array)) {
keyIsList = true;
params[key] = [params[key]];
}
// Lists keys need to be pushed, not assigned.
if (keyIsList) {
// Never-before-seen bracketed keys need their list initialized.
if (!(key in params)) {
params[key] = [];
}
// Pushing undefined does "set" that index in the array. It's cleaner
// to not push it if the key has no value.
if (value !== undefined) {
params[key].push(value);
}
} else {
// Simple assignment for non-list keys.
params[key] = value;
}
});
return params;
};
// Query string unit tests. Returns map of test names to success true/false.
(function (f) {
var tests = [
function normalNonRepeated() {
var p = f('?foo=bar&baz=quz');
return p.foo === 'bar' && p.baz === 'quz';
},
function normalNonRepeatedWithoutQuestionMark() {
var p = f('foo=bar&baz=quz');
return p.foo === 'bar' && p.baz === 'quz';
},
function empty() {
var p = f('?');
return p !== null && p !== undefined && p.constructor === Object;
},
function valuelessWithEquals() {
var p = f('?foo=&baz=quz');
return p.foo === undefined && p.baz === 'quz';
},
function valuelessWithEqualsSimple() {
var p = f('?foo=');
return p.foo === undefined;
},
function valuelessWithoutEquals() {
var p = f('?foo&baz=quz');
return p.foo === undefined && p.baz === 'quz';
},
function valuelessWithoutEqualsSimple() {
var p = f('?foo');
return p.foo === undefined;
},
function repeatedWithoutBrackets() {
var p = f('?foo=bar1&foo=bar2&baz=quz');
return p.foo[0] === 'bar1' && p.foo[1] === 'bar2' && p.baz === 'quz';
},
function repeatedWithBrackets() {
var p = f('?foo[]=bar1&foo[]=bar2&baz=quz');
return p.foo[0] === 'bar1' && p.foo[1] === 'bar2' && p.baz === 'quz';
},
function decodesUrlComponents() {
var p = f('?%E3%81%BB%E3%81%92=%E3%81%BB%E3%81%92');
return p['ほげ'] === 'ほげ';
}
];
var results = {};
tests.forEach(function (testFn) {
var success = false;
try {
success = testFn();
} catch (e) {}
results[testFn.name] = success;
if (!success) {
console.error("Unit testfailed:", testFn.name);
}
});
return results;
}(queryStringToObject));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment