Parse query string in JavaScript [duplicate]
Asked Answered
L

11

415

I need to parse the query string www.mysite.com/default.aspx?dest=aboutus.aspx. How do I get the dest variable in JavaScript?

Luxurious answered 19/1, 2010 at 1:49 Comment(13)
Have a look at this solution. Using his function, you would just not to call gup('dest') to grab the URL dest parameter.Graveclothes
function qs(search_for) { var query = window.location.search.substring(1); var parms = query.split('&'); for (var i = 0; i < parms.length; i++) { var pos = parms[i].indexOf('='); if (pos > 0 && search_for == parms[i].substring(0, pos)) { return parms[i].substring(pos + 1);; } } return ""; } //using : document.write(qs("isFolderLevel"));Clot
codepen.io/iegik/pen/NGRzoY?editors=101Corgi
Old threat but still people are searching for it like me,Here is good snippet gist.github.com/cowboy/1025817Hymnology
I've written a package you might like, uqs, that let's you just do var params = QS.parse(location.search); console.info(params['dest']); // > 'aboutus.aspx'Briton
I just use the query-string package: npmjs.com/package/query-stringConfessional
not a duplicate. getting is different than parsing.Faveolate
There's already a (non IE) function to do this in native javascript, no need to re-invent the wheel: developer.mozilla.org/en-US/docs/Web/API/URLSearchParamsDykes
All the answers for this question are missing one crucial component as specified at url.spec.whatwg.org/#concept-urlencoded-parser -- replacement of the plus sign in query string variable names and values, with space.Mayamayakovski
this is the most compact version: const qs = (qs) => qs.substring(1).split('&').reduce((m, arg) => {const [key, value] = arg.split('='); m[key] = value; return m;}, {});. remember the value that you need to pass to this function should be like this ?aaa=12&b&c the result will be a map of all the keys and values.Sickening
If you need a small, isomorphic solution check out bundlephobia.com/[email protected]Chickpea
Simple solution is var url = "www.mysite.com/default.aspx?dest=aboutus.aspx" var query = new URLSearchParams(url.split("?")[1]) query.get('dest')Clinkstone
The search property of the Location interface provides the query string and most modern browsers provide URLSearchParams to make life easier.Scriabin
T
393

Here is a fast and easy way of parsing query strings in JavaScript:

function getQueryVariable(variable) {
    var query = window.location.search.substring(1);
    var vars = query.split('&');
    for (var i = 0; i < vars.length; i++) {
        var pair = vars[i].split('=');
        if (decodeURIComponent(pair[0]) == variable) {
            return decodeURIComponent(pair[1]);
        }
    }
    console.log('Query variable %s not found', variable);
}

Now make a request to page.html?x=Hello:

console.log(getQueryVariable('x'));
Terrance answered 19/1, 2010 at 5:34 Comment(17)
you should also decode any special characters that have been percent-encodedStatue
Easy, but not very fast if you need to get more than one query value. I think a better abstraction is to return a JS object with all the name value pairs from the query stringSpiegel
Also, the split("=") is not good enough, you can have a "name=value" pair where value contains a non-encoded '='. The solution to that is to do an indexOf('=') to find the first '=', and the substring before and after.Doghouse
what about ?this=1&this=2&this=3Hystero
For CopyPasters out there ;) I'd put console && console.log otherwise there would be JS errors when console doesn't exist which would be the case on your visitor's end.Heelandtoe
@TimothéeGroleau no, the solution is to use split's limit argument: vars[i].split('=', 2)Bryner
@gotofritz, I don't think that does the same thing: "a=b=c".split("=", 2) gives you [ 'a', 'b' ], what you'd want instead is ['a', 'b=c']Doghouse
@TimothéeGroleau true - I always assumed it worked like in PHP - it doesn'tBryner
@TimothéeGroleau and Perl perl -e 'print join(" -- ", split /=/, "a=b=c", 2)' --> a -- b=cLockard
breaks when ?a=b=cWooster
Not to mention this has no clue whatsoever on deeply nested and array values such as: post[title] or post[images][]. Still good for simple stuff though, depending on your (nesting / multi value) needs.Kinsey
Crashes if search is something like ?x&y=3 (don't trust user input). Alternative: const match = window.location.search.substring(1).match(new RegExp(variable + '=([^&]*)')); return match ? match[1] : nullLevin
@DanieleTesta maybe it was long timeHeelandtoe
As many have already pointed out; the solution works but does not cover all cases. The below answer is a better solution imho.Darrelldarrelle
@Znarkus Using a RegExp like that does a ton of superfluous work (including matching many times), and it fails to encode variable for both query string syntax (encodeURIComponent) and RegExp syntax (many special characters must be backslash-escaped). I would not recommend solving a problem with regular expressions that can be solved trivially with indexOf and substring.Binaural
also there will be an issue if you params it base64 string which can contain == at the end and token is not validAvogadro
For later viewers, please see developer.mozilla.org/en-US/docs/Web/API/URLSearchParams !Charcoal
C
202
function parseQuery(queryString) {
    var query = {};
    var pairs = (queryString[0] === '?' ? queryString.substr(1) : queryString).split('&');
    for (var i = 0; i < pairs.length; i++) {
        var pair = pairs[i].split('=');
        query[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1] || '');
    }
    return query;
}

Turns query string like hello=1&another=2 into object {hello: 1, another: 2}. From there, it's easy to extract the variable you need.

That said, it does not deal with array cases such as "hello=1&hello=2&hello=3". To work with this, you must check whether a property of the object you make exists before adding to it, and turn the value of it into an array, pushing any additional bits.

Chimkent answered 16/11, 2012 at 15:15 Comment(10)
if b is an array of one element then this function will fail. ex. somesite.com/?varrible1=data&varrible2= ex. somesite.com/?varrible1=data&varribleHaste
Here are Jasmine tests for this: gist.github.com/amyboyd/68a86fe3f65a77fcfc7fFayth
for (var i in a) fails as it might enumerate object names in addition to array index values.Philbo
sorry i had to downvote - but for (var in..) loops without using hasOwnProperty is extremely bad practice...Canuck
Fixed bugs and updated the code. Sorry, I want to shout it out loud here: "Javascript, why we have to do this manually? Making mistakes! Isn't JS intended to work in browser and help people in web development?Hyoscyamine
Sorry but I didn't get the argument for using hasOwnProperty there, you're doing a split to an array and then looping straight over it, where do you see the danger @jebbie?Guglielmo
well it's corrected now - it's not a "for in" loop anymore which takes out the danger.. in operator will loop over every value of the prototype, so if Array.prototype was extended by some libraries with some funny things, you could end up picking such unwanted stuff too.. most of the cases it's very unlikely but enough so IDE's like web-storm will complain about a missing "hasOwnProperty" check in "for in" loopsCanuck
@Hyoscyamine Yeah, I love parseStr() in PHP.Harborage
This works, just add an if statement to validate pair[0]!="".Lammas
Could be a bit shortened: queryString.replace(/^\?/, '').split('&') Thanks for the solution :)Fresno
P
57

You can also use the excellent URI.js library by Rodney Rehm. Here's how:-

var qs = URI('www.mysite.com/default.aspx?dest=aboutus.aspx').query(true); // == { dest : 'aboutus.aspx' }
    alert(qs.dest); // == aboutus.aspx

And to parse the query string of current page:-

var $_GET = URI(document.URL).query(true); // ala PHP
    alert($_GET['dest']); // == aboutus.aspx 
Patel answered 6/2, 2012 at 14:17 Comment(7)
What does the argument in .query(true) part do? Is it to return the query as a key-value object instead of the query-string?Rai
@bigp Yup .query() returns the query string in foo=bar&hello=world format while .query(true) parses the query string into an object, e.g., { foo : 'bar', hello : 'world' }.Patel
Cool, but solutions requiring 3rd party libraries aren't ideal. I'm somewhat surprised this solution has received so many upvotes. No offense intended to @SalmanPKHarwin
@Harwin But custom, re-inventing the wheel, not battle-tested and very limited functionality solutions are? Interesting ;)Patel
A good native solution is (almost) always better than a good solution requiring a 3rd party tool, is all I'm saying.Harwin
Even so, it's always nice to know such a tool exists. In fact, I know exactly how to parse a query by hand, but I preferred to Google around for some better solution, and that's how I got here, in the first place. ;)Rael
Mind the time gap, but I think if using javascript dependencies didin't have so many inconsistencies (is it ESM or CJS? Does it have typescript bindings? Is it a drop-in JS file for the browser that populates window? Does it export a function, or an object with a property that's a function, or a class, or an object with a class? Is the new keyword necessary? Why, or why not? Is it open for extension?) then it would be the preferred way to do things.Mid
H
26

Me too! http://jsfiddle.net/drzaus/8EE8k/

(Note: without fancy nested or duplicate checking)

deparam = (function(d,x,params,p,i,j) {
return function (qs) {
    // start bucket; can't cheat by setting it in scope declaration or it overwrites
    params = {};
    // remove preceding non-querystring, correct spaces, and split
    qs = qs.substring(qs.indexOf('?')+1).replace(x,' ').split('&');
    // march and parse
    for (i = qs.length; i > 0;) {
        p = qs[--i];
        // allow equals in value
        j = p.indexOf('=');
        // what if no val?
        if(j === -1) params[d(p)] = undefined;
        else params[d(p.substring(0,j))] = d(p.substring(j+1));
    }

    return params;
};//--  fn  deparam
})(decodeURIComponent, /\+/g);

And tests:

var tests = {};
tests["simple params"] = "ID=2&first=1&second=b";
tests["full url"] = "http://blah.com/?third=c&fourth=d&fifth=e";
tests['just ?'] = '?animal=bear&fruit=apple&building=Empire State Building&spaces=these+are+pluses';
tests['with equals'] = 'foo=bar&baz=quux&equals=with=extra=equals&grault=garply';
tests['no value'] = 'foo=bar&baz=&qux=quux';
tests['value omit'] = 'foo=bar&baz&qux=quux';

var $output = document.getElementById('output');
function output(msg) {
    msg = Array.prototype.slice.call(arguments, 0).join("\n");
    if($output) $output.innerHTML += "\n" + msg + "\n";
    else console.log(msg);
}
var results = {}; // save results, so we can confirm we're not incorrectly referencing
$.each(tests, function(msg, test) {
    var q = deparam(test);
    results[msg] = q;
    output(msg, test, JSON.stringify(q), $.param(q));
    output('-------------------');
});

output('=== confirming results non-overwrite ===');
$.each(results, function(msg, result) {
    output(msg, JSON.stringify(result));
    output('-------------------');
});

Results in:

simple params
ID=2&first=1&second=b
{"second":"b","first":"1","ID":"2"}
second=b&first=1&ID=2
-------------------
full url
http://blah.com/?third=c&fourth=d&fifth=e
{"fifth":"e","fourth":"d","third":"c"}
fifth=e&fourth=d&third=c
-------------------
just ?
?animal=bear&fruit=apple&building=Empire State Building&spaces=these+are+pluses
{"spaces":"these are pluses","building":"Empire State Building","fruit":"apple","animal":"bear"}
spaces=these%20are%20pluses&building=Empire%20State%20Building&fruit=apple&animal=bear
-------------------
with equals
foo=bar&baz=quux&equals=with=extra=equals&grault=garply
{"grault":"garply","equals":"with=extra=equals","baz":"quux","foo":"bar"}
grault=garply&equals=with%3Dextra%3Dequals&baz=quux&foo=bar
-------------------
no value
foo=bar&baz=&qux=quux
{"qux":"quux","baz":"","foo":"bar"}
qux=quux&baz=&foo=bar
-------------------
value omit
foo=bar&baz&qux=quux
{"qux":"quux","foo":"bar"}   <-- it's there, i swear!
qux=quux&baz=&foo=bar        <-- ...see, jQuery found it
-------------------
Hoskins answered 16/1, 2013 at 22:14 Comment(9)
just tryin' to keep it simpleHoskins
What if one of the variables in query string includes = (equal) signKenti
@WebolizeR -- considering the value containing = should have been encoded, shouldn't be a problem -- jsfiddle.net/8EE8k/15Hoskins
Fails if any query string value does not have an equal sign, for example: '?val1=1&val2&val3=4', because the split on '=' results in pair[1] == null, which decodeURIComponent(null) returns the string "null" instead of value null. Better to use d(pair[1] || '').Endometriosis
@Endometriosis sure, good point, although technically you'd want to avoid decoding it entirely if it was empty e.g. something like pair[1] ? d(pair[1]) : pair[1]. trivial enough to include for that particular use case. my old answer was meant to be a simple narrowish purpose solution that doesn't involve lots of code.Hoskins
@Hoskins I used your code, but i needed duplicating parameters to be parsed as array. In case somebody have same needs, - jsfiddle.net/sergiyok/yywhxsqzYaroslavl
does not work with array ?test[]=3&test[name]=3Revue
@Hoskins -- = is allowed in a query string value, and it does appear in the wild. In general split should not be used to get a prefix or suffix. At best it does extra work and at worst it causes bugs. A trivial indexOf/lastIndexOf and substring will suffice.Binaural
there, 7+ years later is (almost) everyone happy?Hoskins
O
18

Here's my version based loosely on Braceyard's version above but parsing into a 'dictionary' and support for search args without '='. In use it in my JQuery $(document).ready() function. The arguments are stored as key/value pairs in argsParsed, which you might want to save somewhere...

var args = document.location.search.substring(1).split('&');

var argsParsed = {};

for (i=0; i < args.length; i++)
{
    var arg = decodeURIComponent(args[i]);
    
    if (arg.indexOf('=') == -1)
    {
        argsParsed[arg.trim()] = true;
    }
    else
    {
        var kvp = arg.split('=');
        argsParsed[kvp[0].trim()] = kvp[1].trim();
    }
}
Olethea answered 19/10, 2011 at 19:12 Comment(8)
Is there a reason for using unescape() instead of decodeURI()?Salazar
I would add if(args[i].length){ as the first line in the loop in order to avoid empty keys in argsParsed.Salazar
@ghigo Yes, checking for a zero length key would be a good idea, perhaps after trimming though. There was no reason to use unescape(), I can't remember where I copied it from ;-)Olethea
Warning: unescape is deprecated. See: developer.mozilla.org/en-US/docs/JavaScript/Guide/…Amphibole
Don't use this code, it's just wrong. Trimming modifies data, unescape is used instead of decodeURIComponent and it's called in the wrong place (name and value should be parsed separately, not as a part of the name=value string). It also leaks global variables and uses '==' for comparing values.Kilauea
Trim is probably fine here, since 'space' should be encoded as '+', which, by the way, decodeURIComponent does not decode. In addition to decodeURIComponent, you'd have to replace '+' with ' ' to get the real names and values.Endometriosis
breaks when ?a=b=cWooster
@Endometriosis It is not correct that "'space' should be encoded as '+'." That is one convention used for certain form behaviors, but %20 is also fine in a query string. This is even codified in modern HTML standards.Binaural
T
14

Following on from my comment to the answer @bobby posted, here is the code I would use:

    function parseQuery(str)
        {
        if(typeof str != "string" || str.length == 0) return {};
        var s = str.split("&");
        var s_length = s.length;
        var bit, query = {}, first, second;
        for(var i = 0; i < s_length; i++)
            {
            bit = s[i].split("=");
            first = decodeURIComponent(bit[0]);
            if(first.length == 0) continue;
            second = decodeURIComponent(bit[1]);
            if(typeof query[first] == "undefined") query[first] = second;
            else if(query[first] instanceof Array) query[first].push(second);
            else query[first] = [query[first], second]; 
            }
        return query;
        }

This code takes in the querystring provided (as 'str') and returns an object. The string is split on all occurances of &, resulting in an array. the array is then travsersed and each item in it is split by "=". This results in sub arrays wherein the 0th element is the parameter and the 1st element is the value (or undefined if no = sign). These are mapped to object properties, so for example the string "hello=1&another=2&something" is turned into:

{
hello: "1",
another: "2",
something: undefined
}

In addition, this code notices repeating reoccurances such as "hello=1&hello=2" and converts the result into an array, eg:

{
hello: ["1", "2"]
}

You'll also notice it deals with cases in whih the = sign is not used. It also ignores if there is an equal sign straight after an & symbol.

A bit overkill for the original question, but a reusable solution if you ever need to work with querystrings in javascript :)

Tarshatarshish answered 15/12, 2012 at 22:3 Comment(0)
N
10

If you know that you will only have that one querystring variable you can simply do:

var dest = location.search.replace(/^.*?\=/, '');
Nel answered 9/12, 2010 at 19:28 Comment(3)
Not bad. I'd add this so it is unencoded properly: var dest = unescape(location.search.replace(/^.*\=/, '')).replace(/\+/g, " ");Dingle
Can you modify this to account for a potential anchor on the query string?Morgue
The regex should have a ? after the *. As is, it will fail for a query string of ?dest=foo=bar.Mahala
D
7

The following function will parse the search string with a regular expression, cache the result and return the value of the requested variable:

window.getSearch = function(variable) {
  var parsedSearch;
  parsedSearch = window.parsedSearch || (function() {
    var match, re, ret;
    re = /\??(.*?)=([^\&]*)&?/gi;
    ret = {};
    while (match = re.exec(document.location.search)) {
      ret[match[1]] = match[2];
    }
    return window.parsedSearch = ret;
  })();
  return parsedSearch[variable];
};

You can either call it once without any parameters and work with the window.parsedSearch object, or call getSearch subsequently. I haven't fully tested this, the regular expression might still need some tweaking...

Daugavpils answered 9/10, 2011 at 15:1 Comment(4)
seems like a case of "I have a problem. I'll use some regex to solve it. Now I have two problems." Tell me how this is better than @Braveyard's string parsing method.Dawdle
Like I wrote, it will be parsed once and cached in an object. @Braveyard's code will parse the whole hash each time you call the function, and loop through all available variables until the correct one is found.Daugavpils
@Dawdle regular expressions vs splitting strings is just a matter of taste I guess...Daugavpils
@Dawdle It is better as it is challenging... Though it is a more frustrated programmer's approach..Evening
H
5

How about this?

function getQueryVar(varName){
    // Grab and unescape the query string - appending an '&' keeps the RegExp simple
    // for the sake of this example.
    var queryStr = unescape(window.location.search) + '&';

    // Dynamic replacement RegExp
    var regex = new RegExp('.*?[&\\?]' + varName + '=(.*?)&.*');

    // Apply RegExp to the query string
    var val = queryStr.replace(regex, "$1");

    // If the string is the same, we didn't find a match - return false
    return val == queryStr ? false : val;
}

..then just call it with:

alert('Var "dest" = ' + getQueryVar('dest'));

Cheers

Harwin answered 21/11, 2011 at 22:30 Comment(2)
Downvoter, would appreciate an explanation...Harwin
You should first split at & and then unescape. Otherwise, this code surely fails if the value contains an encoded & or =, especially if it repeats parts of the keywordBawd
H
4

I wanted a simple function that took a URL as an input and returned a map of the query params. If I were to improve this function, I would support the standard for array data in the URL, and or nested variables.

This should work back and for with the jQuery.param( qparams ) function.

function getQueryParams(url){
    var qparams = {},
        parts = (url||'').split('?'),
        qparts, qpart,
        i=0;

    if(parts.length <= 1 ){
        return qparams;
    }else{
        qparts = parts[1].split('&');
        for(i in qparts){

            qpart = qparts[i].split('=');
            qparams[decodeURIComponent(qpart[0])] = 
                           decodeURIComponent(qpart[1] || '');
        }
    }

    return qparams;
};
Haste answered 21/12, 2012 at 4:49 Comment(8)
if(parts.length <= 1 ){ created bit of confusion...Evening
breaks when ?a=b=cWooster
@Wooster In what situations is ?a=b=c used?Dagger
@ShannonMatthews if you want to pass the string "b=c" to the parameter "a". or any value containing the '=' character. the above code assumes the value does not contain a '='.Wooster
Thanks @Spongman.Dagger
technically only the key value pair is allowed to use the '=' sign un-escaped. ( = %3D) w3schools.com/tags/ref_urlencode.ASP URL Reserved Characters tools.ietf.org/html/rfc3986#section-2.2 URL Path Parameters tools.ietf.org/html/rfc3986#section-3.3 so the real question is should your code work with URLs that are not in spec, that might be a requirement for your project, but usually it's not unless you have a special case.Haste
the spec doesn't involve itself in the semantics of the encoding of the key & value fields in the query. but, obviously, if you don't want your implementation to be broken, then you should encode/decode these appropriately, as do most implementations. the above code is broken in general, don't use it.Wooster
@Spongman, the spec in 2.2 literally calls the '=' sign a reserved character and says it's safe for delimiting the parts of the url. the other parts of the spec detail how to have 'reserved characters' in the rest of the URL by encoding them. if you have an unencoded '=' and the intent is not part of the Key/Value Pair then the URL should fail validation, and is out of spec. like i said, maybe you have a site you are working with and you need to parse a url scheme that violates spec, but that shouldn't be the default.Haste
C
1

I wanted to pick up specific links within a DOM element on a page, send those users to a redirect page on a timer and then pass them onto the original clicked URL. This is how I did it using regular javascript incorporating one of the methods above.

Page with links: Head

  function replaceLinks() {   
var content = document.getElementById('mainContent');
            var nodes = content.getElementsByTagName('a');
        for (var i = 0; i < document.getElementsByTagName('a').length; i++) {
            {
                href = nodes[i].href;
                if (href.indexOf("thisurl.com") != -1) {

                    nodes[i].href="http://www.thisurl.com/redirect.aspx" + "?url=" + nodes[i];
                    nodes[i].target="_blank";

                }
            }
    }
}

Body

<body onload="replaceLinks()">

Redirect page Head

   function getQueryVariable(variable) {
        var query = window.location.search.substring(1);
        var vars = query.split('&');
        for (var i = 0; i < vars.length; i++) {
            var pair = vars[i].split('=');
            if (decodeURIComponent(pair[0]) == variable) {
                return decodeURIComponent(pair[1]);
            }
        }
        console.log('Query variable %s not found', variable);
    }
    function delayer(){
        window.location = getQueryVariable('url')
    }

Body

<body onload="setTimeout('delayer()', 1000)">
Cough answered 21/11, 2012 at 16:50 Comment(2)
Welcome to Stack Overflow. Is this a Question?Josefjosefa
Nope, I thought it might be useful to share an example of the parser in action.Cough

© 2022 - 2024 — McMap. All rights reserved.