JavaScript Query String
Posted by Chris | Filed under JavaScript
Query Strings
When I started coding more client-side JavaScript in replace of ASP.NET code, I was surprised to find there there's no object in JavaScript that breaks down a query string into a key (or name)/value collection, as
Here's a URL with a query string:
http://prettycode.com/search?query=code&pageSize=20
The query string is everything that including and after the
As a Collection In JavaScript?
One would think that as prevalent as the use of query strings are for passing parameters to web servers, there would be an object in JavaScript that served as a collection of these pairs hung off of
The property
// same as: alert("?query=code&pageSize=20"); alert(window.location.search);
If there’s no query string (e.g. at the URL http://prettycode.org),
// same as: alert(""); alert(window.location.search);
Introducing window.location.querystring
In lieu of such a name/value object, I’ve written a very simple JavaScript that represents the query string as a dictionary object. The object’s members are the query string names, and the member values are the name values. Make your life easier and drop the window.location.querystring script somewhere in your global scope. Using the script is as simple as:
var querystring = window.location.querystring; var myValue = querystring["myKey"]; for (var key in querystring) { var value = querystring[key]; alert(key + "=" + value); }
Here it is, with no dependencies:
window.location.querystring = (function() { // by Chris O'Brien, prettycode.org var collection = {}; // Gets the query string, starts with '?' var querystring = window.location.search; // Empty if no query string if (!querystring) { return { toString: function() { return ""; } }; } // Decode query string and remove '?' querystring = decodeURI(querystring.substring(1)); // Load the key/values of the return collection var pairs = querystring.split("&"); for (var i = 0; i < pairs.length; i++) { // Empty pair (e.g. ?key=val&&key2=val2) if (!pairs[i]) { continue; } // Don't use split("=") in case value has "=" in it var seperatorPosition = pairs[i].indexOf("="); if (seperatorPosition == -1) { collection[pairs[i]] = ""; } else { collection[pairs[i].substring(0, seperatorPosition)] = pairs[i].substr(seperatorPosition + 1); } } // toString() returns the key/value pairs concatenated collection.toString = function() { return "?" + querystring; }; return collection; })();
Edge Cases
Ah yes, those annoying what-ifs. How are malformed or missing query strings or parameter values handled? Take a look.
Pair Doesn't Exist
If you're expecting a key/value pair, but it isn't present,
// http://prettycode.org/?pageSize=20 if (!window.location.querystring["q"]) // == undefined alert("You forgot to enter a query");
No Query String
If there is no query string, window.location.querystring.toString() returns an empty string, like Request.QueryString.ToSring() does in ASP.NET:
// http://prettycode.org if (!window.location.querystring.toString()) // == "" alert("No query string");
No Name/Value Pairs
If there are no name/value pairs, window.location.querystring's only member is toString(), and it will return the value of window.location.search, decoded:
// http://prettycode.org/? var s = window.location.querystring.toString(); // == "?"
Missing Parameter Value
If a query string parameter is specified but has no value, the value is an empty string, also ASP.NET style:
// http://prettycode.org/?query=&pageSize=20 if (!window.location.querystring["query"]) // == "" alert("No query specified");
Incomplete Pair
If there's at least one pair and additional data in the query string that isn't a pair, it's added with an empty value:
// http://prettycode.org/?query=seattle&pageSize var querystring = window.location.querystring; var query = querystring["query"]; // == "seattle" var pageSize = querystring["pageSize"]; // == "" if (!pageSize) { pageSize = 20; }
Multiple Pairs with the same Name
Lastly, if the parameter name is specified twice, its value will the be the last defined:
// http://prettycode.org/?query=seattle&query=portland var query = window.location.querystring["query"]; // == "portland"
Tags: ASP.NET, JavaScript, query string, querystring
April 22nd, 2009 at 7:00 am
Why no make toString just return window.location.search? Saves encoding what you just decoded.
April 22nd, 2009 at 9:39 am
You are voted!
Track back from http://webdevvote.com
April 22nd, 2009 at 12:57 pm
You can use this method:
April 22nd, 2009 at 8:34 pm
@Miron: While that works, every time GetQuerystringParam() is invoked, the URL has mutiple regular expressions matched against it, which is bad practice. The URL should be broken down into a collection or examined for a name/value pair once; not every time a query string parameter value is needed.
April 22nd, 2009 at 8:38 pm
@Garry: Good point. In response, I’ve changed the script to avoid manually rebuilding the decoded query string toString() returns, and instead, the decodedlocation.search value is returned by toString(). Thanks again!
April 24th, 2009 at 2:54 am
In other hand, why should you parse all the query string parameters when you need only one?
Also, you are talking about client side code and regular expression over not so long string… The performance impact is negligible.
April 24th, 2009 at 10:54 am
@Miron: I don’t think the GetQuerystringParam() you’ve shown is a bad tool. My concern with using it is that it’s easily abused because it’s a function. What if another developer is maintaining the app. and wants to grab another value in the query string? They’ll likely just call the same function you used. The consequence isn’t performance (as you say, it’s negligible). Code should be written with reuse in mind, and defensively against misuse—as a practice. A function encourages repetitious, procedural, imperative design, while an object encourages encapsulation, separation of concerns, and adherence to DRY. The consequence (at least in my mind) is that such a function has greater potential to encourage sloppy code.
I think what is probably a great idea is replacing the name/value parsing logic in my code with the regular expressions you’re using if the regex is bulletproof.